Variable: RDateTimeField
const RDateTimeField: DefineComponent<ExtractPropTypes<AppendDefault<{
active: BooleanConstructor;
allowUnspecifiedChoices: {
default: boolean;
type: BooleanConstructor;
};
autocomplete: PropType<string>;
autofocus: BooleanConstructor;
baseColor: StringConstructor;
bgColor: StringConstructor;
choices: {
default: undefined;
type: PropType<any[] | undefined>;
};
class: PropType<any>;
clearable: BooleanConstructor;
clearIcon: Omit<{
default: string;
type: PropType<IconValue>;
}, "type" | "default"> & {
default: | NonNullable<IconValue>
| () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>;
type: PropType<
| IconValue
| () => VNode<RendererNode, RendererElement, {
[key: ...]: ...;
}>>;
};
color: StringConstructor;
datePickerIcon: {
default: () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>;
type: PropType<IconValue>;
};
dateTerm: {
default: undefined;
type: PropType<string | undefined>;
};
density: {
default: string;
type: PropType<Density>;
validator: (v: any) => boolean;
};
direction: {
default: string;
type: PropType<"vertical" | "horizontal">;
validator: (v: any) => boolean;
};
dirty: BooleanConstructor;
disabled: {
default: null;
type: BooleanConstructor;
};
displayFormat: {
default: string;
type: PropType<
| "short"
| "shortWithSeconds"
| "med"
| "medWithSeconds"
| "medWithWeekday"
| "full"
| "fullWithSeconds"
| "huge"
| "hugeWithSeconds">;
};
displayLocale: {
default: undefined;
type: PropType<string | undefined>;
};
displayTimezone: {
default: undefined;
type: PropType<string | Zone<boolean> | undefined>;
};
error: BooleanConstructor;
errorMessages: {
default: () => never[];
type: PropType<string | readonly string[] | null>;
};
firstDayOfWeek: {
default: undefined;
type: (NumberConstructor | StringConstructor)[];
};
flat: BooleanConstructor;
focused: BooleanConstructor;
glow: BooleanConstructor;
hideDetails: PropType<boolean | "auto">;
hint: StringConstructor;
href: StringConstructor;
iconColor: (StringConstructor | BooleanConstructor)[];
id: StringConstructor;
label: {
default: undefined;
type: PropType<string | undefined>;
};
loading: (StringConstructor | BooleanConstructor)[];
max: {
default: undefined;
type: PropType<string | Date | DateTime<boolean> | null | undefined>;
};
maxErrors: {
default: number;
type: (NumberConstructor | StringConstructor)[];
};
maxWidth: (NumberConstructor | StringConstructor)[];
menuIcon: Omit<{
default: string;
type: PropType<IconValue>;
}, "type" | "default"> & {
default: | NonNullable<IconValue>
| () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>;
type: PropType<
| IconValue
| () => VNode<RendererNode, RendererElement, {
[key: ...]: ...;
}>>;
};
messages: {
default: () => never[];
type: PropType<string | readonly string[]>;
};
min: {
default: undefined;
type: PropType<string | Date | DateTime<boolean> | null | undefined>;
};
minWidth: (NumberConstructor | StringConstructor)[];
modeIcon: Omit<{
default: string;
type: PropType<IconValue>;
}, "type" | "default"> & {
default: | NonNullable<IconValue>
| () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>;
type: PropType<
| IconValue
| () => VNode<RendererNode, RendererElement, {
[key: ...]: ...;
}>>;
};
modelValue: {
default: undefined;
type: PropType<string | string[] | null | undefined>;
};
multiple: {
default: boolean;
type: PropType<boolean>;
};
name: StringConstructor;
nextIcon: Omit<{
default: string;
type: PropType<IconValue>;
}, "type" | "default"> & {
default: | NonNullable<IconValue>
| () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>;
type: PropType<
| IconValue
| () => VNode<RendererNode, RendererElement, {
[key: ...]: ...;
}>>;
};
noValuesText: {
default: undefined;
type: PropType<string | undefined>;
};
onBlur: {
default: undefined;
type: PropType<() => void | undefined>;
};
onChange: {
default: undefined;
type: PropType<() => void | undefined>;
};
onClick:append?: PropType<(...args: [MouseEvent]) => void | undefined>;
onClick:appendInner?: PropType<(...args: [MouseEvent]) => void | undefined>;
onClick:clear?: PropType<(...args: [MouseEvent]) => void | undefined>;
onClick:control?: PropType<(...args: [MouseEvent]) => void | undefined>;
onClick:prepend?: PropType<(...args: [MouseEvent]) => void | undefined>;
onClick:prependInner?: PropType<(...args: [MouseEvent]) => void | undefined>;
onInput: {
default: undefined;
type: PropType<() => void | undefined>;
};
onMousedown:control?: PropType<(...args: [MouseEvent]) => void | undefined>;
onUpdate:focused?: PropType<(...args: [boolean]) => void | undefined>;
onUpdate:model-value?: PropType<(...args: [string | ...[] | null]) => void | undefined>;
onUpdate:modelValue?: PropType<(...args: [string | ...[] | null]) => void | undefined>;
persistentClear: BooleanConstructor;
persistentHint: BooleanConstructor;
persistentPlaceholder: BooleanConstructor;
placeholder: StringConstructor;
prefix: StringConstructor;
prevIcon: Omit<{
default: string;
type: PropType<IconValue>;
}, "type" | "default"> & {
default: | NonNullable<IconValue>
| () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>;
type: PropType<
| IconValue
| () => VNode<RendererNode, RendererElement, {
[key: ...]: ...;
}>>;
};
readonly: {
default: null;
type: PropType<boolean | null>;
};
renderMode: {
default: string;
type: PropType<"edit" | "read">;
};
reverse: BooleanConstructor;
role: {
default: string;
type: PropType<string>;
};
rounded: {
default: undefined;
type: (NumberConstructor | StringConstructor | BooleanConstructor)[];
};
showWeek: BooleanConstructor;
singleLine: BooleanConstructor;
style: {
default: null;
type: PropType<StyleValue>;
};
suffix: StringConstructor;
theme: StringConstructor;
tile: BooleanConstructor;
timePickerFormat: {
default: string;
type: PropType<"24hr" | "ampm">;
};
timePickerIcon: {
default: () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>;
type: PropType<IconValue>;
};
timeTerm: {
default: undefined;
type: PropType<string | undefined>;
};
timezonePickerIcon: {
default: () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>;
type: PropType<IconValue>;
};
timezoneTerm: {
default: undefined;
type: PropType<string | undefined>;
};
to: PropType<
| string
| RouteLocationAsRelativeGeneric
| RouteLocationAsPathGeneric>;
validateOn: PropType<
| "eager"
| "input"
| "blur"
| "submit"
| "invalid-input"
| "input lazy"
| "blur lazy"
| "submit lazy"
| "invalid-input lazy"
| "input eager"
| "blur eager"
| "submit eager"
| "invalid-input eager"
| "lazy input"
| "lazy blur"
| "lazy submit"
| "lazy invalid-input"
| "eager input"
| "eager blur"
| "eager submit"
| "eager invalid-input"
| "lazy"
| undefined>;
variant: {
default: string;
type: PropType<
| "outlined"
| "plain"
| "underlined"
| "filled"
| "solo"
| "solo-inverted"
| "solo-filled">;
validator: (v: any) => boolean;
};
width: (NumberConstructor | StringConstructor)[];
}, {
}>>, () =>
| VNode<RendererNode, RendererElement, {
[key: string]: any;
}>
| null, {
}, {
}, {
}, ComponentOptionsMixin, ComponentOptionsMixin, EmitFunctions<{
click:append: (...args: [MouseEvent]) => boolean;
click:appendInner: (...args: [MouseEvent]) => boolean;
click:clear: (...args: [MouseEvent]) => boolean;
click:control: (...args: [MouseEvent]) => boolean;
click:prepend: (...args: [MouseEvent]) => boolean;
click:prependInner: (...args: [MouseEvent]) => boolean;
mousedown:control: (...args: [MouseEvent]) => boolean;
update:focused: (...args: [boolean]) => boolean;
update:model-value: (value: string | string[] | null | undefined) => boolean;
update:modelValue: (value: string | string[] | null | undefined) => boolean;
}>, string, PublicProps, ToResolvedProps<ExtractPropTypes<AppendDefault<{
active: BooleanConstructor;
allowUnspecifiedChoices: {
default: boolean;
type: BooleanConstructor;
};
autocomplete: PropType<string>;
autofocus: BooleanConstructor;
baseColor: StringConstructor;
bgColor: StringConstructor;
choices: {
default: undefined;
type: PropType<any[] | undefined>;
};
class: PropType<any>;
clearable: BooleanConstructor;
clearIcon: Omit<{
default: string;
type: PropType<IconValue>;
}, "type" | "default"> & {
default: | NonNullable<IconValue>
| () => VNode<RendererNode, RendererElement, {
[key: ...]: ...;
}>;
type: PropType<
| IconValue
| () => VNode<..., ..., ...>>;
};
color: StringConstructor;
datePickerIcon: {
default: () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>;
type: PropType<IconValue>;
};
dateTerm: {
default: undefined;
type: PropType<string | undefined>;
};
density: {
default: string;
type: PropType<Density>;
validator: (v: any) => boolean;
};
direction: {
default: string;
type: PropType<"vertical" | "horizontal">;
validator: (v: any) => boolean;
};
dirty: BooleanConstructor;
disabled: {
default: null;
type: BooleanConstructor;
};
displayFormat: {
default: string;
type: PropType<
| "short"
| "shortWithSeconds"
| "med"
| "medWithSeconds"
| "medWithWeekday"
| "full"
| "fullWithSeconds"
| "huge"
| "hugeWithSeconds">;
};
displayLocale: {
default: undefined;
type: PropType<string | undefined>;
};
displayTimezone: {
default: undefined;
type: PropType<string | Zone<boolean> | undefined>;
};
error: BooleanConstructor;
errorMessages: {
default: () => never[];
type: PropType<string | readonly string[] | null>;
};
firstDayOfWeek: {
default: undefined;
type: (NumberConstructor | StringConstructor)[];
};
flat: BooleanConstructor;
focused: BooleanConstructor;
glow: BooleanConstructor;
hideDetails: PropType<boolean | "auto">;
hint: StringConstructor;
href: StringConstructor;
iconColor: (StringConstructor | BooleanConstructor)[];
id: StringConstructor;
label: {
default: undefined;
type: PropType<string | undefined>;
};
loading: (StringConstructor | BooleanConstructor)[];
max: {
default: undefined;
type: PropType<string | Date | DateTime<boolean> | null | undefined>;
};
maxErrors: {
default: number;
type: (NumberConstructor | StringConstructor)[];
};
maxWidth: (NumberConstructor | StringConstructor)[];
menuIcon: Omit<{
default: string;
type: PropType<IconValue>;
}, "type" | "default"> & {
default: | NonNullable<IconValue>
| () => VNode<RendererNode, RendererElement, {
[key: ...]: ...;
}>;
type: PropType<
| IconValue
| () => VNode<..., ..., ...>>;
};
messages: {
default: () => never[];
type: PropType<string | readonly string[]>;
};
min: {
default: undefined;
type: PropType<string | Date | DateTime<boolean> | null | undefined>;
};
minWidth: (NumberConstructor | StringConstructor)[];
modeIcon: Omit<{
default: string;
type: PropType<IconValue>;
}, "type" | "default"> & {
default: | NonNullable<IconValue>
| () => VNode<RendererNode, RendererElement, {
[key: ...]: ...;
}>;
type: PropType<
| IconValue
| () => VNode<..., ..., ...>>;
};
modelValue: {
default: undefined;
type: PropType<string | string[] | null | undefined>;
};
multiple: {
default: boolean;
type: PropType<boolean>;
};
name: StringConstructor;
nextIcon: Omit<{
default: string;
type: PropType<IconValue>;
}, "type" | "default"> & {
default: | NonNullable<IconValue>
| () => VNode<RendererNode, RendererElement, {
[key: ...]: ...;
}>;
type: PropType<
| IconValue
| () => VNode<..., ..., ...>>;
};
noValuesText: {
default: undefined;
type: PropType<string | undefined>;
};
onBlur: {
default: undefined;
type: PropType<() => void | undefined>;
};
onChange: {
default: undefined;
type: PropType<() => void | undefined>;
};
onClick:append?: PropType<(...args: [MouseEvent]) => void | undefined>;
onClick:appendInner?: PropType<(...args: [MouseEvent]) => void | undefined>;
onClick:clear?: PropType<(...args: [MouseEvent]) => void | undefined>;
onClick:control?: PropType<(...args: [MouseEvent]) => void | undefined>;
onClick:prepend?: PropType<(...args: [MouseEvent]) => void | undefined>;
onClick:prependInner?: PropType<(...args: [MouseEvent]) => void | undefined>;
onInput: {
default: undefined;
type: PropType<() => void | undefined>;
};
onMousedown:control?: PropType<(...args: [MouseEvent]) => void | undefined>;
onUpdate:focused?: PropType<(...args: [boolean]) => void | undefined>;
onUpdate:model-value?: PropType<(...args: [... | ... | ... | ...]) => void | undefined>;
onUpdate:modelValue?: PropType<(...args: [... | ... | ... | ...]) => void | undefined>;
persistentClear: BooleanConstructor;
persistentHint: BooleanConstructor;
persistentPlaceholder: BooleanConstructor;
placeholder: StringConstructor;
prefix: StringConstructor;
prevIcon: Omit<{
default: string;
type: PropType<IconValue>;
}, "type" | "default"> & {
default: | NonNullable<IconValue>
| () => VNode<RendererNode, RendererElement, {
[key: ...]: ...;
}>;
type: PropType<
| IconValue
| () => VNode<..., ..., ...>>;
};
readonly: {
default: null;
type: PropType<boolean | null>;
};
renderMode: {
default: string;
type: PropType<"edit" | "read">;
};
reverse: BooleanConstructor;
role: {
default: string;
type: PropType<string>;
};
rounded: {
default: undefined;
type: (NumberConstructor | StringConstructor | BooleanConstructor)[];
};
showWeek: BooleanConstructor;
singleLine: BooleanConstructor;
style: {
default: null;
type: PropType<StyleValue>;
};
suffix: StringConstructor;
theme: StringConstructor;
tile: BooleanConstructor;
timePickerFormat: {
default: string;
type: PropType<"24hr" | "ampm">;
};
timePickerIcon: {
default: () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>;
type: PropType<IconValue>;
};
timeTerm: {
default: undefined;
type: PropType<string | undefined>;
};
timezonePickerIcon: {
default: () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>;
type: PropType<IconValue>;
};
timezoneTerm: {
default: undefined;
type: PropType<string | undefined>;
};
to: PropType<
| string
| RouteLocationAsRelativeGeneric
| RouteLocationAsPathGeneric>;
validateOn: PropType<
| "eager"
| "input"
| "blur"
| "submit"
| "invalid-input"
| "input lazy"
| "blur lazy"
| "submit lazy"
| "invalid-input lazy"
| "input eager"
| "blur eager"
| "submit eager"
| "invalid-input eager"
| "lazy input"
| "lazy blur"
| "lazy submit"
| "lazy invalid-input"
| "eager input"
| "eager blur"
| "eager submit"
| "eager invalid-input"
| "lazy"
| undefined>;
variant: {
default: string;
type: PropType<
| "outlined"
| "plain"
| "underlined"
| "filled"
| "solo"
| "solo-inverted"
| "solo-filled">;
validator: (v: any) => boolean;
};
width: (NumberConstructor | StringConstructor)[];
}, {
}>>, EmitFunctions<{
click:append: (...args: [MouseEvent]) => boolean;
click:appendInner: (...args: [MouseEvent]) => boolean;
click:clear: (...args: [MouseEvent]) => boolean;
click:control: (...args: [MouseEvent]) => boolean;
click:prepend: (...args: [MouseEvent]) => boolean;
click:prependInner: (...args: [MouseEvent]) => boolean;
mousedown:control: (...args: [MouseEvent]) => boolean;
update:focused: (...args: [boolean]) => boolean;
update:model-value: (value: string | string[] | null | undefined) => boolean;
update:modelValue: (value: string | string[] | null | undefined) => boolean;
}>>, {
active: boolean;
allowUnspecifiedChoices: boolean;
autofocus: boolean;
choices: any[] | undefined;
clearable: boolean;
clearIcon: | IconValue
| () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>;
datePickerIcon: IconValue;
dateTerm: string | undefined;
density: Density;
direction: "vertical" | "horizontal";
dirty: boolean;
disabled: boolean;
displayFormat: | "short"
| "shortWithSeconds"
| "med"
| "medWithSeconds"
| "medWithWeekday"
| "full"
| "fullWithSeconds"
| "huge"
| "hugeWithSeconds";
displayLocale: string | undefined;
displayTimezone: string | Zone<boolean> | undefined;
error: boolean;
errorMessages: string | readonly string[] | null;
firstDayOfWeek: string | number;
flat: boolean;
focused: boolean;
glow: boolean;
label: string | undefined;
max: string | Date | DateTime<boolean> | null | undefined;
maxErrors: string | number;
menuIcon: | IconValue
| () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>;
messages: string | readonly string[];
min: string | Date | DateTime<boolean> | null | undefined;
modeIcon: | IconValue
| () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>;
modelValue: string | string[] | null | undefined;
multiple: boolean;
nextIcon: | IconValue
| () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>;
noValuesText: string | undefined;
onBlur: () => void | undefined;
onChange: () => void | undefined;
onInput: () => void | undefined;
persistentClear: boolean;
persistentHint: boolean;
persistentPlaceholder: boolean;
prevIcon: | IconValue
| () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>;
readonly: boolean | null;
renderMode: "edit" | "read";
reverse: boolean;
role: string;
rounded: string | number | boolean;
showWeek: boolean;
singleLine: boolean;
style: StyleValue;
tile: boolean;
timePickerFormat: "24hr" | "ampm";
timePickerIcon: IconValue;
timeTerm: string | undefined;
timezonePickerIcon: IconValue;
timezoneTerm: string | undefined;
variant: | "outlined"
| "plain"
| "underlined"
| "filled"
| "solo"
| "solo-inverted"
| "solo-filled";
}, SlotsType<Partial<{
append: (arg: VInputSlot) => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>[];
append-inner: (arg: DefaultInputSlot) => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>[];
clear: (arg: DefaultInputSlot & {
props: Record<string, any>;
}) => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>[];
counter: (arg: VCounterSlot) => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>[];
default: (arg: {
id: Readonly<Ref<string, string>>;
}) => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>[];
details: (arg: VInputSlot) => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>[];
label: (arg: DefaultInputSlot & {
label: string | undefined;
props: Record<string, any>;
}) => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>[];
loader: (arg: LoaderSlotProps) => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>[];
message: (arg: VMessageSlot) => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>[];
prepend: (arg: VInputSlot) => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>[];
prepend-inner: (arg: DefaultInputSlot) => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>[];
}>>, {
}, {
}, string, ComponentProvideOptions, true, {
}, any>;RDateTimeField - A sophisticated Vue component for ISO 8601 datetime input with full timezone support.
This component provides the most comprehensive datetime input solution available, combining the accessibility and validation benefits of HTML5 datetime inputs with a completely custom visual interface. It features a triple-layer picker system (date, time, timezone) with intelligent mobile optimization and robust timezone handling.
Key Features
- Triple Input Interface: Integrated VDatePicker + VTimePicker + TimezonePicker
- Mobile Optimized: VBottomSheet with tabs on mobile, VDialog on desktop
- ISO 8601 Standard: All datetimes stored as ISO strings with full timezone information
- Luxon Integration: Advanced datetime parsing, formatting, and timezone manipulation
- Browser UI Suppression: Custom pickers while preserving HTML5 benefits
- Multiple Values: Chip-based interface for datetime arrays
- Smart Constraints: Min/max datetime validation with timezone boundary awareness
- Visual Timezone Selection: Interactive world map with autocomplete fallback
- Intelligent Readonly: Mobile inputs become readonly to prevent keyboard conflicts
- Advanced Validation: Ensures valid ISO datetimes with timezone compliance
Technical Architecture
The component uses a sophisticated multi-layer picker approach:
Base Layer (RCustomField)
- Built on the refactored RCustomField for consistent behavior
- HTML5 date/time input types for validation and mobile optimization
- Injected CSS suppresses all native browser datetime picker UI
- Maintains accessibility and semantic benefits
Date Layer (VDatePicker)
- Full calendar navigation with month/year/decade selection
- Configurable constraints with timezone-aware min/max validation
- Visual indication of constraint violations through tab styling
Time Layer (VTimePicker)
- 12/24 hour format support with optional seconds precision
- Smart time constraints based on selected date and global bounds
- Analog and digital time input methods
Timezone Layer (Custom TimezonePicker)
- Interactive SVG world map with IANA timezone regions
- Autocomplete VCombobox for quick timezone search
- Real-time preview of selected timezone with offset display
- Integration with system timezone detection and browser APIs
Mobile Layer (Touch Optimization)
- Input becomes readonly on mobile to prevent keyboard conflicts
- onClick:control handler analyzes click position for smart focusing
- VBottomSheet with tabbed interface for optimal touch navigation
- Tab indicators show which sections need completion (date/time/timezone)
Validation Layer
- Ensures ISO 8601 compliance with timezone extensions
- Validates timezone names against IANA database
- Luxon-based parsing for robust datetime validation
- Cross-timezone constraint validation for min/max bounds
Data Flow
- Input: User interacts with date picker, time picker, or timezone map
- Local State: Individual components (date, time, timezone) update local reactive state
- Combination: Computed property combines parts using Luxon DateTime.fromSQL()
- Validation: Luxon validates combined datetime and timezone
- Serialization: Valid datetime converted to ISO 8601 with timezone extension
- Storage: ISO string stored in modelValue with proper timezone information
- Display: Luxon formats for presentation using displayFormat and locale
- Emission: Validated ISO string emitted to parent component
Usage Patterns
Example
<template>
<!-- Basic datetime selection -->
<RDateTimeField
v-model="selectedDateTime"
label="Select Date & Time"
displayFormat="med"
/>
<!-- Advanced configuration -->
<RDateTimeField
v-model="meetingTime"
label="Meeting Time"
displayFormat="fullWithSeconds"
timePickerFormat="24hr"
:min="DateTime.now().toISO()"
:max="DateTime.now().plus({ months: 6 }).toISO()"
:firstDayOfWeek="1"
:showWeek="true"
/>
<!-- Multiple datetimes -->
<RDateTimeField
v-model="eventSchedule"
multiple
label="Event Schedule"
displayFormat="medWithWeekday"
:min="todayISO"
timePickerFormat="24hr"
/>
<!-- Read-only display -->
<RDateTimeField
v-model="historicalEvents"
multiple
render-mode="read"
displayFormat="huge"
/>
<!-- Custom terminology -->
<RDateTimeField
v-model="appointmentTime"
label="Appointment"
dateTerm="Date"
timeTerm="Time"
timezoneTerm="Location"
displayFormat="full"
/>
</template>Timezone Intelligence
The component provides sophisticated timezone handling:
- IANA Support: Full IANA timezone database integration
- DST Awareness: Automatic daylight saving time transitions
- Fixed Offsets: Support for non-IANA fixed offset timezones
- Visual Selection: Interactive world map for intuitive timezone picking
- Search Interface: Autocomplete for quick timezone lookup
- System Integration: Automatic detection of user's system timezone
- Smart Input Handling: Handles both object and string values from combobox selection
Constraint Validation
Advanced min/max constraint system:
- Cross-timezone: Constraints work across different timezone selections
- Smart Time Limits: Time picker adapts based on selected date and constraints
- Visual Feedback: Tab indicators show constraint violations
- Impossible States: Clever use of impossible time ranges for invalid date selections
Performance Characteristics
- Computed Properties: Efficient reactive updates using Vue 3's computed system
- Luxon Caching: Leverages Luxon's internal caching for datetime operations
- Lazy Rendering: Picker components only render when dialog is open
- Memory Management: Proper cleanup of event listeners and reactive state
Browser Compatibility
Automatic CSS injection handles native picker suppression across:
- WebKit: Safari, Chrome, Edge (webkit-calendar-picker-indicator)
- Mozilla: Firefox (moz-calendar-picker-indicator)
- Microsoft: Legacy Edge, IE (ms-clear, ms-reveal)
This ensures consistent custom UI while preserving HTML5 input benefits like validation, accessibility, and mobile keyboard optimization.