@razorpay/blade-mcp
Version:
Model Context Protocol server for Blade
343 lines (297 loc) • 9.6 kB
Markdown
The TimePicker component is a comprehensive time selection input that supports both 12-hour and 24-hour formats with configurable minute step intervals. It features an accessible segmented input field where users can directly type or use dropdown/bottom sheet selection with scrollable spin wheels. The component provides responsive layouts with desktop dropdown and mobile bottom sheet, includes validation states, and supports both controlled and uncontrolled usage patterns.
- `timeFormat` only accepts `'12h'` or `'24h'` values
- `minuteStep` only accepts `1`, `5`, `15`, or `30` as valid values
- `size` only accepts `'medium'` or `'large'` values
- `labelPosition` only accepts `'top'` or `'left'` values
- When using controlled mode, both `value` and `onChange` props must be provided
- `onApply` callback is only triggered when `showFooterActions` is `true` and user clicks Apply button
- Component requires a valid Date object or null for `value` and `defaultValue` props
- `validationState` only accepts `'error'`, `'success'`, or `'none'` values
These types define the props that the TimePicker component and its related components accept. Use these for proper TypeScript integration and to understand available configuration options.
```typescript
/**
* Time format types supported by TimePicker
* Both 12h and 24h formats are supported using React Aria.
*/
type TimeFormat = '12h' | '24h';
/**
* Minute step intervals supported by TimePicker
*/
type MinuteStep = 1 | 5 | 15 | 30;
/**
* Value object returned by TimePicker onChange and onApply callbacks
* Designed for future extensibility while maintaining backwards compatibility
*/
type TimePickerValue = {
/**
* The selected time as a Date object
*/
value: Date | null;
};
/**
* Individual time component identifiers
*/
type TimePart = 'hour' | 'minute' | 'period';
type TimePickerCommonInputProps = {
inputRef?: React.Ref<any>;
referenceProps?: any;
} & Pick<
BaseInputProps,
| 'labelPosition'
| 'size'
| 'isRequired'
| 'necessityIndicator'
| 'autoFocus'
| 'isDisabled'
| 'accessibilityLabel'
| 'name'
| 'placeholder'
| 'label'
| 'onFocus'
| 'onBlur'
| 'labelSuffix'
| 'labelTrailing'
> &
FormInputValidationProps;
/**
* Main TimePicker component props
* Combines input functionality with time selection capabilities
*/
type TimePickerProps = Omit<
TimePickerInputProps,
'inputRef' | 'refrenceProps' | 'successText' | 'errorText' | 'helpText' | 'time' | 'onChange'
> &
Omit<TimePickerSelectorProps, 'isOpen' | 'defaultIsOpen' | 'onOpenChange' | 'time'> & {
/**
* Current time value as Date object (for controlled usage)
*/
value?: Date | null;
/**
* Callback fired when time value changes
* @param timeValue - Object containing the selected time
*/
onChange?: (timeValue: TimePickerValue) => void;
/**
* Label for the time input
*/
label?: string;
/**
* Help text to guide the user
*/
helpText?: string;
/**
* Error text to show validation errors
*/
errorText?: string;
/**
* Success text to show validation success
*/
successText?: string;
/**
* Controls dropdown open state (for controlled usage)
* @default false
*/
isOpen?: boolean;
/**
* Default open state (for uncontrolled usage)
* @default false
*/
defaultIsOpen?: boolean;
/**
* Callback fired when dropdown open state changes
* @param state - Object containing the new open state
*/
onOpenChange?: (state: { isOpen: boolean }) => void;
/**
* Test ID for testing purposes
*/
testID?: string;
/**
* Accessibility label for screen readers
* When not provided, falls back to label prop
*/
accessibilityLabel?: string;
};
type TimePickerSelectorProps = {
/**
* Current time value as Date object (for controlled usage)
*/
time?: Date | null;
/**
* Default time value as Date object (for uncontrolled usage)
*/
defaultValue?: Date;
/**
* Callback fired when time value changes during selection
* @param timeValue - Object containing the selected time and future extensible properties
*/
onChange?: (timeValue: TimePickerValue) => void;
/**
* Time format for display and interaction
* @default "12h"
*
* Both 12h and 24h formats are supported using React Aria.
*/
timeFormat?: TimeFormat;
/**
* Controls dropdown open state (for controlled usage)
* @default false
*/
isOpen?: boolean;
/**
* Default open state (for uncontrolled usage)
* @default false
*/
defaultIsOpen?: boolean;
/**
* Step interval for minutes selection
* @default 1
* @example 15 // allows 00, 15, 30, 45 minutes only
*/
minuteStep?: MinuteStep;
/**
* Callback fired when dropdown open state changes
* @param state - Object containing the new open state
*/
onOpenChange?: (state: { isOpen: boolean }) => void;
/**
* Whether to show the apply/cancel buttons in the dropdown
* @default true
*
* When true:
* - Shows Apply/Cancel buttons for explicit confirmation
* - User must click Apply to confirm selection
* - Better for complex time selections
*
* When false:
* - On blur, selected time will automatically apply and close the dropdown
* - Pressing Enter immediately applies the current selection and closes
* - More streamlined interaction experience
*/
showFooterActions?: boolean;
/**
* Callback fired when user applies time selection
* Only called when showFooterActions is true and user clicks Apply
* @param timeValue - Object containing the confirmed time value
*/
onApply?: (timeValue: TimePickerValue) => void;
/**
* To set the controlled value of the time picker
*/
setControlledValue?: (time: Date | null) => void;
size?: 'medium' | 'large';
};
/**
* Props for individual time column components (Hours, Minutes, Period)
*/
type TimeColumnProps = {
values: string[];
selectedValue: string;
onValueChange: (value: string) => void;
};
/**
* Props for time picker footer actions (Apply/Cancel buttons)
*/
type TimePickerFooterProps = {
onApply: () => void;
onCancel: () => void;
isApplyDisabled?: boolean;
};
type TimeSegmentProps = {
segment: DateSegment;
state: TimeFieldState;
isDisabled?: boolean;
};
```
```tsx
import React, { useState } from 'react';
import {
TimePicker,
Box,
Button,
Link,
Tooltip,
TooltipInteractiveWrapper,
InfoIcon,
} from '@razorpay/blade/components';
function TimePickerExample() {
const [basicTime, setBasicTime] = useState<Date | null>(null);
const [advancedTime, setAdvancedTime] = useState<Date | null>(null);
const [isOpen, setIsOpen] = useState(false);
const [hasError, setHasError] = useState(false);
// Validation for business hours (9 AM - 6 PM)
const validateTime = (time: Date | null) => {
if (!time) return;
const hour = time.getHours();
setHasError(hour < 9 || hour >= 18);
};
return (
<Box display="flex" flexDirection="column" gap="spacing.5">
{/* Basic TimePicker - shows common usage */}
<TimePicker
label="Meeting Time"
timeFormat="12h"
size="medium"
value={basicTime}
onChange={({ value }) => setBasicTime(value)}
showFooterActions={false}
minuteStep={15}
helpText="Select your meeting time (15-minute intervals)"
placeholder="Select time"
accessibilityLabel="Select meeting time"
/>
{/* Advanced TimePicker - shows all advanced features */}
<TimePicker
label="Business Hours Appointment"
labelPosition="top"
labelSuffix={
<Tooltip content="Must be during business hours (9 AM - 6 PM)" placement="right">
<TooltipInteractiveWrapper display="flex">
<InfoIcon size="small" color="surface.icon.gray.muted" />
</TooltipInteractiveWrapper>
</Tooltip>
}
labelTrailing={<Link size="small">Time zones</Link>}
timeFormat="24h"
size="large"
value={advancedTime}
defaultValue={new Date('2024-01-01T14:30:00')}
onChange={({ value }) => {
setAdvancedTime(value);
validateTime(value);
}}
onApply={({ value }) => console.log('Applied:', value)}
isOpen={isOpen}
onOpenChange={({ isOpen }) => setIsOpen(isOpen)}
isRequired
necessityIndicator="required"
validationState={hasError ? 'error' : advancedTime ? 'success' : 'none'}
errorText={hasError ? 'Please select time during business hours (9 AM - 6 PM)' : undefined}
successText={!hasError && advancedTime ? 'Valid appointment time' : undefined}
showFooterActions={true}
minuteStep={30}
isDisabled={false}
autoFocus={false}
name="appointment-time"
testID="advanced-timepicker"
accessibilityLabel="Select appointment time during business hours"
/>
{/* Control buttons to demonstrate programmatic usage */}
<Box display="flex" gap="spacing.3">
<Button size="small" onClick={() => setAdvancedTime(new Date())}>
Set Current Time
</Button>
<Button size="small" variant="secondary" onClick={() => setIsOpen(!isOpen)}>
Toggle Dropdown
</Button>
</Box>
</Box>
);
}
```