Changelog
All notable changes to this project are documented here
🚀
Current Version
v4.2.1 - Released March 18, 2026
Version 4.2.1 - March 18, 2026
Fixed
- Plugin type declarations - Plugin .d.ts files (range, timezone, wheel) used 'never' for factory parameters, causing PluginRegistry.register() to reject plugins in strict TypeScript projects
Version 4.2.0 - March 18, 2026
Added
- Wheel mode - Scroll-spinner interface replacing the analog clock face. Enable via ui.mode: 'wheel'. Supports 12h/24h, all themes, disabled time, and keyboard navigation
- Compact-wheel mode - Headerless wheel picker without the hour/minute inputs header. Enable via ui.mode: 'compact-wheel'. Combine with wheel.placement for popover positioning
- wheel.placement option - Popover placement ('auto', 'top', 'bottom') for compact-wheel mode. Opens as a popover anchored to the input instead of a centered modal
- wheel.hideDisabled option - Completely remove disabled hours/minutes from the wheel list instead of dimming them. Only applies to wheel and compact-wheel modes
- wheel.commitOnScroll option - Auto-commit time at the end of wheel scrolling without pressing OK. Only applies to wheel and compact-wheel modes
- Clear button - Reset time selection with a dedicated clear button. Enabled by default via ui.clearButton option
- clearBehavior.clearInput option - Control whether clearing also empties the input field value (default: true)
- labels.clear option - Customize the clear button text (default: "Clear")
- onClear callback and clear event - New callback and EventEmitter event with previousValue payload
- New exported types - ClearEventData, ClearBehaviorOptions, WheelScrollStartEventData, WheelScrollEndEventData
- wheel.ignoreOutsideClick option - Prevent the picker from closing when clicking outside its area. Only applies to wheel and compact-wheel modes
Fixed
- Rapid-click race condition - Rapidly clicking the input before the modal fully opened could cause the picker to remain invisible in the DOM or permanently block the input element
- Range plugin landscape layout - From/To header tabs were mispositioned in landscape orientation. Fixed with proper absolute positioning within the grid layout
- Timezone plugin landscape layout - Timezone picker was broken in landscape orientation. Implemented CSS Grid layout that properly positions header, timezone selector, and clock face side by side
- AM/PM border color in landscape - Hardcoded black border replaced with theme-aware var(--tp-border) variable
- Compact-wheel popover viewport detection - Popover did not flip from bottom to top early enough near the viewport edge. Added safety threshold, switched to accurate visible viewport measurement, and improved fallback to prefer the side with more space
- PluginFactory type safety - PluginFactory type now correctly accepts CoreState and EventEmitter parameters instead of using any/never workarounds. Removed unsafe type assertions from the plugin registry
Version 4.1.7 - March 8, 2026
Fixed
- Range plugin 12h AM/PM sync - AM/PM state desynchronization when switching between From/To tabs. Clock now correctly syncs internal AM/PM state with saved range values
Version 4.1.6 - February 14, 2026
Fixed
- Range plugin minute disabling - Minutes were incorrectly disabled for all hours in TO picker instead of only for the FROM hour. Now minutes are blocked only when TO hour equals FROM hour (both 12h and 24h modes)
- setValue() method - Fixed setValue() not working correctly when called programmatically after initialization
Version 4.1.5 - February 10, 2026
Fixed
- DisabledTime update() method - update() now properly calls getDisableTime() to refresh disabled time state after options change
Version 4.1.4 - February 9, 2026
Fixed
- iOS Mobile hover state fix - v4.1.3 didn't fix the hover bug on all mobile devices, especially iOS Safari. Enhanced CSS with additional touch-action properties and improved media query specificity to completely prevent hover state persistence on all mobile browsers
- Range mode validation - OK button now correctly disabled when end time ≤ start time. AM/PM changes automatically trigger validation to prevent invalid range selection
Version 4.1.3 - February 9, 2026
Fixed
- Mobile hover state persistence - Fixed hover state remaining on hour/minute inputs and AM/PM buttons after touch events on mobile devices
- Range mode AM/PM state - Fixed AM/PM remaining selected when switching from filled 'from' to empty 'to' in range mode
- Range mode input updates - Input value now updates only on confirm instead of during selection in range mode
- Mobile view class assignment - Added missing mobile class to wrapper-type-time, AM/PM buttons and input-ripple-wrapper when toggling mobile view
- Input readonly removal on view switch - Fixed readonly attribute not being removed when switching from desktop to mobile view with enableSwitchIcon
- Dynamic input validation on view switch - Mobile input validation now works when switching views - blur handlers check readonly attribute dynamically instead of static options
Added
- Range plugin TypeScript types - Exported RangeOptions, RangeConfirmEventData, RangeSwitchEventData, RangeValidationEventData for better type safety
Version 4.1.2 - February 8, 2026
Fixed
- Range button text visibility - Fixed text visibility in range buttons for crane, crane-straight, dark and cyberpunk themes
- Documentation examples - Corrected timezone option property name from defaultTimezone to default in all examples
Added
- Auto-switch to minutes - Hour and minute input elements automatically update active state when hour is selected on desktop
Version 4.1.1 - February 1, 2026
Fixed
- Mobile input validation - Fixed issue where invalid time values (e.g., 169:70) could be entered via keyboard in mobile mode. Inputs now auto-clamp to valid ranges
Internal
- Test coverage - Expanded test suite to 1100+ tests with 90%+ code coverage
Version 4.1.0 - January 31, 2026
Added
- Plugin architecture - Range and Timezone as optional plugins - import only what you need for smaller bundles
- Smooth hour snapping - New smoothHourSnap option (default: true) enables fluid hour dragging with animation
- Range mode time blocking - When from time is selected, to picker automatically disables earlier times with visual feedback
- Timezone dropdown theming - CSS variables --tp-dropdown-option-bg and --tp-dropdown-option-text for consistent styling
Changed
- Modular bundle structure - Core bundle no longer includes Range and Timezone code. Reduces default bundle size
- Smooth hour dragging is now default - smoothHourSnap defaults to true. Set to false for legacy discrete jump behavior
Version 4.0.3 - January 23, 2026
Fixed
- Desktop/mobile view switching - Fixed enableSwitchIcon toggle not updating label text (Select time ↔ Enter time), icon (keyboard ↔ schedule), and Hour/Minute label visibility
Version 4.0.2 - November 23, 2025
Fixed
- Firefox Compatibility - Fixed 'TouchEvent is not defined' error in DragHandlers - changed from instanceof TouchEvent to 'touches' in event check
Added
- Exported Grouped Option Types - Added exports for TimepickerOptions, ClockOptions, UIOptions, LabelsOptions, BehaviorOptions, CallbacksOptions to support type-safe option composition
- onUpdate Event Emissions - Added missing onUpdate event emissions in EventManager and ClockManager for real-time value synchronization
Firefox Fix Details
// Before (causing error on Firefox)if (event instanceof TouchEvent) { // ❌ TouchEvent not definedconst touch = event.touches[0];}// After (cross-browser compatible)if ('touches' in event) { // ✅ Works everywhereconst touch = event.touches[0];}
Version 4.0.1 - November 21, 2025
Fixed
- TypeScript Callback Types - All callback functions now have proper generic types instead of unknown
- Type-safe Event Payloads - onConfirm, onOpen, onUpdate, and other callbacks now correctly infer event data types
- Improved IntelliSense - Full autocomplete for event data properties without requiring manual type annotations
Before (4.0.0)
// Callbacks had unknown typescallbacks: {onConfirm: (data) => {// data: unknown - no autocomplete ❌console.log(data.hour); // TypeScript error}}
After (4.0.1)
// Callbacks are now properly typedcallbacks: {onConfirm: (data) => {// data: ConfirmEventData - full autocomplete ✅console.log(data.hour); // string | undefinedconsole.log(data.minutes); // string | undefinedconsole.log(data.type); // string | undefined}}
Version 4.0.0 - November 21, 2025
⚠️ BREAKING CHANGES - Migration Required
All CSS class names and CSS variable names have been renamed:
// CSS Class Names (ALL classes changed)- .timepicker-ui-*+ .tp-ui-*Examples:- .timepicker-ui-wrapper → .tp-ui-wrapper- .timepicker-ui-modal → .tp-ui-modal- .timepicker-ui-clock-face → .tp-ui-clock-face- .timepicker-ui-hour → .tp-ui-hour- .timepicker-ui-minutes → .tp-ui-minutes- .timepicker-ui-am → .tp-ui-am- .timepicker-ui-pm → .tp-ui-pm- .timepicker-ui-ok-btn → .tp-ui-ok-btn- .timepicker-ui-cancel-btn → .tp-ui-cancel-btn// CSS Variables (ALL variables changed)- --timepicker-*+ --tp-*Examples:- --timepicker-bg → --tp-bg- --timepicker-primary → --tp-primary- --timepicker-text → --tp-text- --timepicker-surface → --tp-surface- --timepicker-border → --tp-border- --timepicker-shadow → --tp-shadow- --timepicker-border-radius → --tp-border-radius- --timepicker-font-family → --tp-font-family// Options Structure (GROUPED)// v3.x (flat - DEPRECATED):-{- clockType: '24h',- theme: 'dark',- animation: true,- amLabel: 'AM',- onConfirm: (data) => {}-}// v4.0.0 (grouped - NEW):+{+ clock: {+ type: '24h'+ },+ ui: {+ theme: 'dark',+ animation: true+ },+ labels: {+ am: 'AM'+ },+ callbacks: {+ onConfirm: (data) => {}+ }+}// Migration Steps:1. Find & replace all CSS class names in your stylesheets2. Find & replace all CSS variable names in your custom themes3. Reorganize options into groups: clock, ui, labels, behavior, callbacks4. Update clockType → clock.type, theme → ui.theme, onConfirm → callbacks.onConfirm5. Test all customizations and themes thoroughly
Important: The NPM package name remains timepicker-ui. Only CSS classes and variables changed.
Changed (Breaking)
- CSS Class Renaming - All .timepicker-ui-* classes renamed to .tp-ui-*
- CSS Variable Renaming - All --timepicker-* variables renamed to --tp-*
- Options Structure Reorganization - Options now grouped into: clock, ui, labels, behavior, callbacks
- Legacy DOM Events Removed - timepicker:* custom events completely removed - use EventEmitter API or callbacks
- setTheme() Method Removed - Programmatic theming removed - use CSS classes with CSS variables instead
Added
- EventEmitter API with Callback Bridge - All 9 callback options automatically bridge to EventEmitter with on(), off(), once() methods
- SSR-Safe Architecture - All modules can be imported in Node.js (Next.js, Nuxt, Remix, Astro compatible)
- Composition-Based Architecture - Pure composition with CoreState, Managers, Lifecycle - no inheritance, fully testable
- Auto-Focus Improvements - Modal auto-focuses on open, minutes auto-focus with autoSwitchToMinutes
- TypeScript Enhancements - No any types, fully typed event payloads, grouped options types, stricter type safety
Changed
- Architecture Refactored - Composition-only pattern - removed all extends, pure dependency injection
- Bundle Size Reduced - 80 KB → 63.3 KB ESM (-20.9%)
- Theme Count - 11 → 10 themes (removed theme-custom from production)
- Event System Unified - Single source of truth - callbacks bridge to EventEmitter automatically
- Options API Restructured - 40+ flat options → 5 logical groups
Removed
- Legacy DOM Events - timepicker:open, timepicker:confirm, timepicker:cancel, etc. - use picker.on() instead
- setTheme() Method - Programmatic theme setting removed - use CSS classes instead
- theme-custom - Removed from production bundle - users create custom themes via CSS variables
Fixed
- Focus Trap Auto-Focus - Modal wrapper auto-focuses on open (no Tab press needed)
- Auto-Switch Focus - Minute input receives focus when autoSwitchToMinutes enabled
- SSR Compatibility - No DOM globals during initialization - safe for server rendering
- currentTime Parsing - Simplified time parsing for better reliability
- Dynamic Updates - Fixed React useEffect patterns to prevent infinite loops
Benefits
- Shorter class names - Reduced HTML size and improved readability
- Smaller bundle - -20.9% bundle size reduction (80 KB → 63.3 KB)
- Better DX - Cleaner API with grouped options and EventEmitter
- SSR Compatible - Works seamlessly with Next.js, Nuxt, Remix, Astro
- Type Safety - No any types, fully typed events and options
Version 3.2.0 - November 14, 2025
Added
- Material Design 3 Ripple Effect - Interactive ripple animations on buttons and inputs
- M3 Color System - Complete color token implementation with CSS variables
- M2 Legacy Theme - Material Design 2 theme (theme: 'm2')
- Mobile Clock Face Toggle - Expand/collapse clock face with smooth animations
- Desktop to Mobile Switching - Dynamic view switching via enableSwitchIcon
- Local SVG Icon Assets - Built-in keyboard.svg and schedule.svg icons
- New ClockSystem Architecture - Three-layer Engine → Controller → Renderer with RAF batching
Changed
- Theme Naming (Breaking) - Renamed 'm3' → 'm3-green'
- Option Naming (Breaking) - Renamed 'switchToMinutesAfterSelectHour' → 'autoSwitchToMinutes'
- ConfigManager Refactoring - Split into 4 modules (87% code reduction)
- Code Quality - KISS/DRY optimization - longest method 225→18 lines (-92%)
Fixed
- Clock face state bugs - Fixed mobile ↔ desktop switching issues
- Animation performance - Removed will-change causing resize lag
- Angle Jump Bug - Fixed Math.atan2() parameter order
- Disabled minutes styling - Visual state now reflects configuration
- 24h positioning - Fixed inner/outer circle dimensions
- 24h click overlap - Reduced threshold and element size
- ClockFace disappears early - Destroy after modal animation completes
- Landscape layout - Fixed expansion direction and class system
- Desktop init bug - Removed incorrect .mobile class
- autoSwitchToMinutes regression - Fixed feature after ClockSystem refactor
Performance
- 60fps transitions - Multi-phase RAF scheduling
- ClockSystem gains - Rendering 15ms→3ms, Drag 8ms→2ms, -25% code size
Migration Guide
Breaking Changes:
// Theme rename- theme: 'm3'+ theme: 'm3-green'// Option rename- switchToMinutesAfterSelectHour: true+ autoSwitchToMinutes: true
Previous Versions
Version 3.1.2
Nov 7, 2025- • Fixed CSS variable issues with var(--timepicker-text)
- • Resolved input color styling problems
Version 3.1.1
Nov 7, 2025- • Virtual DOM caching - 25% performance improvement
- • RAF batching for smoother animations
- • Input sanitization for XSS protection
Version 3.1.0
Nov 7, 2025- • EventEmitter API - on(), once(), off()
- • Deprecated DOM events - migrate to EventEmitter
📖
Full Changelog
View the complete changelog with all versions on GitHub