timepicker-ui 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,60 +1,58 @@
1
1
  # timepicker-ui
2
2
 
3
- > ⚠️ **Upgrading from v2 to v3?**
4
- > Major changes were introduced in version 3.0.
5
- > 👉 [Click here to view the Upgrade Guide](#📈-upgrade-guide-v2-→-v3)
6
-
7
- A modern, lightweight, and fully customizable time picker library built with TypeScript. Features Google's Material Design principles with extensive theming support and framework-agnostic architecture.
3
+ Modern time picker library built with TypeScript. Works with any framework or vanilla JavaScript.
8
4
 
9
5
  [![npm version](https://badge.fury.io/js/timepicker-ui.svg)](https://badge.fury.io/js/timepicker-ui)
10
6
  [![downloads](https://img.shields.io/npm/dw/timepicker-ui)](https://npmcharts.com/compare/timepicker-ui?minimal=true)
11
7
  [![license](https://img.shields.io/badge/license-MIT-green.svg)](https://img.shields.io/npm/l/timepicker-ui)
12
8
 
13
- ---
9
+ [Live Demo](https://timepicker-ui.vercel.app/) • [Documentation](https://timepicker-ui.vercel.app/docs) • [Changelog](./CHANGELOG.md)
14
10
 
15
- ## 📦 Live Demo
11
+ **Upgrading from v2?** Check the [upgrade guide](#upgrade-guide-v2--v3) below.
16
12
 
17
- Curious how it works in practice?
18
- 👉 [Click here to see live examples](https://timepicker-ui.vercel.app/)
13
+ ## Features
19
14
 
20
- ---
15
+ - 9 built-in themes (Material, Crane, Dark, Glassmorphic, Cyberpunk, and more)
16
+ - Mobile-first design with touch support
17
+ - Framework agnostic - works with React, Vue, Angular, Svelte, or vanilla JS
18
+ - Full TypeScript support
19
+ - Inline mode for always-visible timepicker
20
+ - ARIA-compliant and keyboard accessible
21
+ - SSR compatible
22
+ - Lightweight with tree-shaking support
21
23
 
22
- ## Features
24
+ ## Known Limitations
23
25
 
24
- - 🎨 **9 Built-in Themes** Material, Crane, Dark, Glassmorphic, Cyberpunk, AI, and more
25
- - 📱 **Mobile-First Design** — Responsive with touch and keyboard support
26
- - 🚀 **Framework Agnostic** — Works with vanilla JS, React, Vue, Angular, and others
27
- - 🔧 **TypeScript Support** — Full type definitions and IntelliSense
28
- - 🎯 **Inline Mode** — Always-visible timepicker without modal overlay
29
- - 🛠️ **Rich API** — Comprehensive methods and event system
30
- - ♿ **Accessible** — ARIA-compliant with keyboard navigation
31
- - 🌐 **SSR Compatible** — Works with Next.js, Nuxt, and other SSR frameworks
32
- - 📦 **Lightweight** — Minimal footprint with tree-shaking support
26
+ This project is actively maintained. Some areas planned for improvement:
33
27
 
34
- ## 🧭 Roadmap & Known Limitations
28
+ - No unit/integration tests yet
29
+ - Some files need refactoring
30
+ - A few `any` types remain in the codebase
31
+ - No performance monitoring
35
32
 
36
- This project is actively maintained and evolving. Some areas are planned for future improvements:
33
+ Contributions welcome! Feel free to [open an issue or PR](https://github.com/pglejzer/timepicker-ui/issues).
37
34
 
38
- - ❌ No formal tests (unit/integration) — **planned for future releases**
39
- - ❌ Some files are too large — **will be split/refactored**
40
- - ❌ A few `any` types in the codebase — **will be replaced with strict typings**
41
- - ❌ No performance monitoring — **planned metrics/logging in dev mode**
35
+ ## Installation
42
36
 
43
- If you're interested in contributing to any of these areas, feel free to [open an issue or pull request](https://github.com/pglejzer/timepicker-ui/issues)!
37
+ ```bash
38
+ npm install timepicker-ui
39
+ ```
44
40
 
45
- ---
41
+ ## Important: Global CSS Required
46
42
 
47
- ## 🚀 Installation
43
+ Your app needs this global CSS rule for correct styling:
48
44
 
49
- ```bash
50
- npm install timepicker-ui
51
- # or
52
- yarn add timepicker-ui
45
+ ```css
46
+ *,
47
+ *::before,
48
+ *::after {
49
+ box-sizing: border-box;
50
+ }
53
51
  ```
54
52
 
55
- ---
53
+ Most projects include this by default.
56
54
 
57
- ## 📖 Quick Start
55
+ ## Quick Start
58
56
 
59
57
  ### Basic Usage
60
58
 
@@ -64,6 +62,7 @@ yarn add timepicker-ui
64
62
 
65
63
  ```javascript
66
64
  import { TimepickerUI } from "timepicker-ui";
65
+ import "timepicker-ui/main.css";
67
66
 
68
67
  const input = document.querySelector("#timepicker");
69
68
  const picker = new TimepickerUI(input);
@@ -78,15 +77,19 @@ const picker = new TimepickerUI(input, {
78
77
  clockType: "24h",
79
78
  animation: true,
80
79
  backdrop: true,
80
+ onConfirm: (data) => {
81
+ console.log("Selected time:", data);
82
+ },
81
83
  });
82
84
  picker.create();
83
85
  ```
84
86
 
85
- ### React Integration
87
+ ### React Example
86
88
 
87
89
  ```tsx
88
90
  import { useEffect, useRef } from "react";
89
91
  import { TimepickerUI } from "timepicker-ui";
92
+ import "timepicker-ui/main.css";
90
93
 
91
94
  function TimePickerComponent() {
92
95
  const inputRef = useRef<HTMLInputElement>(null);
@@ -108,439 +111,264 @@ function TimePickerComponent() {
108
111
  }
109
112
  ```
110
113
 
111
- ---
112
-
113
- ## ⚙️ Configuration Options
114
-
115
- | Option | Type | Default | Description |
116
- | -------------------------------- | ------------------- | --------------- | ---------------------------------------------------- |
117
- | `amLabel` | `string` | `"AM"` | Custom text for AM label |
118
- | `animation` | `boolean` | `true` | Enable/disable open/close animations |
119
- | `appendModalSelector` | `string` | `""` | DOM selector to append timepicker (defaults to body) |
120
- | `backdrop` | `boolean` | `true` | Show/hide backdrop overlay |
121
- | `cancelLabel` | `string` | `"CANCEL"` | Text for cancel button |
122
- | `clockType` | `"12h" \| "24h"` | `"12h"` | Clock format type |
123
- | `cssClass` | `string` | `undefined` | Additional CSS class for timepicker wrapper |
124
- | `currentTime` | `boolean \| object` | `undefined` | Set current time to input and picker |
125
- | `delayHandler` | `number` | `300` | Debounce delay for buttons (ms) |
126
- | `disabledTime` | `object` | `undefined` | Disable specific hours, minutes, or intervals |
127
- | `editable` | `boolean` | `false` | Allow manual input editing |
128
- | `enableScrollbar` | `boolean` | `false` | Keep page scroll when picker is open |
129
- | `enableSwitchIcon` | `boolean` | `false` | Show desktop/mobile switch icon |
130
- | `focusInputAfterCloseModal` | `boolean` | `false` | Focus input after closing modal |
131
- | `focusTrap` | `boolean` | `true` | Trap focus within modal |
132
- | `hourMobileLabel` | `string` | `"Hour"` | Hour label for mobile version |
133
- | `iconTemplate` | `string` | Material Icons | HTML template for desktop switch icon |
134
- | `iconTemplateMobile` | `string` | Material Icons | HTML template for mobile switch icon |
135
- | `id` | `string` | `undefined` | Custom ID for timepicker instance |
136
- | `incrementHours` | `number` | `1` | Hour increment step (1, 2, 3) |
137
- | `incrementMinutes` | `number` | `1` | Minute increment step (1, 5, 10, 15) |
138
- | `inline` | `object` | `undefined` | Inline mode configuration |
139
- | `minuteMobileLabel` | `string` | `"Minute"` | Minute label for mobile version |
140
- | `mobile` | `boolean` | `false` | Force mobile version |
141
- | `mobileTimeLabel` | `string` | `"Enter Time"` | Time label for mobile version |
142
- | `okLabel` | `string` | `"OK"` | Text for OK button |
143
- | `pmLabel` | `string` | `"PM"` | Custom text for PM label |
144
- | `switchToMinutesAfterSelectHour` | `boolean` | `true` | Auto-switch to minutes after hour selection |
145
- | `theme` | Theme | `"basic"` | UI theme (see themes section) |
146
- | `timeLabel` | `string` | `"Select Time"` | Time label for desktop version |
147
-
148
- ### Inline Mode Configuration
114
+ ## Configuration
115
+
116
+ Full documentation available at [timepicker-ui.vercel.app/docs](https://timepicker-ui.vercel.app/docs)
117
+
118
+ ### Key Options
119
+
120
+ | Option | Type | Default | Description |
121
+ | -------------------------------- | ------------- | ----------- | --------------------------------- |
122
+ | `clockType` | `12h` / `24h` | `12h` | Clock format |
123
+ | `theme` | string | `basic` | UI theme (9 themes available) |
124
+ | `animation` | boolean | `true` | Enable animations |
125
+ | `backdrop` | boolean | `true` | Show backdrop overlay |
126
+ | `editable` | boolean | `false` | Allow manual input editing |
127
+ | `mobile` | boolean | `false` | Force mobile version |
128
+ | `disabledTime` | object | `undefined` | Disable specific hours/minutes |
129
+ | `incrementHours` | number | `1` | Hour increment step |
130
+ | `incrementMinutes` | number | `1` | Minute increment step |
131
+ | `switchToMinutesAfterSelectHour` | boolean | `true` | Auto-switch to minutes after hour |
132
+ | `okLabel` | string | `OK` | OK button text |
133
+ | `cancelLabel` | string | `CANCEL` | Cancel button text |
134
+ | `onConfirm` | function | `undefined` | Callback when time is confirmed |
135
+ | `onCancel` | function | `undefined` | Callback when cancelled |
136
+ | `onOpen` | function | `undefined` | Callback when picker opens |
137
+ | `onUpdate` | function | `undefined` | Callback when time is updated |
138
+ | `onSelectHour` | function | `undefined` | Callback when hour is selected |
139
+ | `onSelectMinute` | function | `undefined` | Callback when minute is selected |
140
+ | `onSelectAM` | function | `undefined` | Callback when AM is selected |
141
+ | `onSelectPM` | function | `undefined` | Callback when PM is selected |
142
+ | `onError` | function | `undefined` | Callback when error occurs |
143
+
144
+ ### Themes
145
+
146
+ Available themes: `basic`, `crane-straight`, `crane-radius`, `m3`, `dark`, `glassmorphic`, `pastel`, `ai`, `cyberpunk`
149
147
 
150
148
  ```javascript
149
+ import "timepicker-ui/main.css"; // Required base styles
150
+ import "timepicker-ui/theme-dark.css"; // Specific theme
151
+
151
152
  const picker = new TimepickerUI(input, {
152
- inline: {
153
- enabled: true,
154
- containerId: "timepicker-container",
155
- showButtons: false, // Hide OK/Cancel buttons
156
- autoUpdate: true, // Auto-update input on change
157
- },
153
+ theme: "dark",
158
154
  });
159
155
  ```
160
156
 
161
- ### Disabled Time Configuration
157
+ ### Disabled Time
162
158
 
163
159
  ```javascript
164
160
  const picker = new TimepickerUI(input, {
165
161
  disabledTime: {
166
- hours: [1, 3, 5, 8], // Disable specific hours
167
- minutes: [15, 30, 45], // Disable specific minutes
168
- interval: "10:00 AM - 2:00 PM", // Disable time range
162
+ hours: [1, 3, 5, 8],
163
+ minutes: [15, 30, 45],
164
+ interval: "10:00 AM - 2:00 PM",
169
165
  },
170
166
  });
171
167
  ```
172
168
 
173
- ---
174
-
175
- ## 🎨 Themes
176
-
177
- > **Note:** As of v3.0, you must import CSS styles manually. See [Upgrade Guide](#upgrade-guide-v2--v3) for details.
178
-
179
- Choose from 9 built-in themes:
180
-
181
- | Theme | Description |
182
- | ---------------- | -------------------------------------- |
183
- | `basic` | Default Material Design theme |
184
- | `crane-straight` | Google Crane theme with straight edges |
185
- | `crane-radius` | Google Crane theme with rounded edges |
186
- | `m3` | Material Design 3 (Material You) |
187
- | `dark` | Dark mode theme |
188
- | `glassmorphic` | Modern glass effect |
189
- | `pastel` | Soft pastel colors |
190
- | `ai` | Futuristic AI-inspired theme |
191
- | `cyberpunk` | Neon cyberpunk aesthetic |
192
-
193
- ```javascript
194
- const picker = new TimepickerUI(input, {
195
- theme: "cyberpunk",
196
- });
197
- ```
198
-
199
- ---
200
-
201
- ## 📞 Callbacks
202
-
203
- Configure callback functions to handle timepicker events:
204
-
205
- | Callback | Type | Description |
206
- | ---------------- | ---------------- | ---------------------------------------------- |
207
- | `onOpen` | `(data) => void` | Triggered when timepicker opens |
208
- | `onCancel` | `(data) => void` | Triggered when picker is cancelled |
209
- | `onConfirm` | `(data) => void` | Triggered when time is confirmed (OK clicked) |
210
- | `onUpdate` | `(data) => void` | Triggered during clock interaction (real-time) |
211
- | `onSelectHour` | `(data) => void` | Triggered when hour mode is activated |
212
- | `onSelectMinute` | `(data) => void` | Triggered when minute mode is activated |
213
- | `onSelectAM` | `(data) => void` | Triggered when AM is selected |
214
- | `onSelectPM` | `(data) => void` | Triggered when PM is selected |
215
- | `onError` | `(data) => void` | Triggered when invalid time format is detected |
216
-
217
- ### Callback Data Structure
218
-
219
- ```typescript
220
- interface CallbackData {
221
- hour?: string;
222
- minutes?: string;
223
- type?: string; // 'AM' or 'PM'
224
- degreesHours?: number;
225
- degreesMinutes?: number;
226
- error?: string; // Only for onError
227
- // ... additional context data
228
- }
229
- ```
230
-
231
- ### Example Usage
169
+ ### Inline Mode
232
170
 
233
171
  ```javascript
234
172
  const picker = new TimepickerUI(input, {
235
- onConfirm: (data) => {
236
- console.log(`Time selected: ${data.hour}:${data.minutes} ${data.type}`);
237
- },
238
- onCancel: (data) => {
239
- console.log("User cancelled time selection");
240
- },
241
- onError: (data) => {
242
- alert(`Invalid time format: ${data.error}`);
173
+ inline: {
174
+ enabled: true,
175
+ containerId: "timepicker-container",
176
+ showButtons: false,
177
+ autoUpdate: true,
243
178
  },
244
179
  });
245
180
  ```
246
181
 
247
- ---
248
-
249
- ## 🎯 Events
250
-
251
- Listen to DOM events dispatched on the input element:
252
-
253
- | Event | Description |
254
- | -------------------------- | ---------------------------------- |
255
- | `timepicker:open` | Fired when timepicker opens |
256
- | `timepicker:cancel` | Fired when user cancels |
257
- | `timepicker:confirm` | Fired when time is confirmed |
258
- | `timepicker:update` | Fired during clock interaction |
259
- | `timepicker:select-hour` | Fired when hour mode is selected |
260
- | `timepicker:select-minute` | Fired when minute mode is selected |
261
- | `timepicker:select-am` | Fired when AM is selected |
262
- | `timepicker:select-pm` | Fired when PM is selected |
263
- | `timepicker:error` | Fired when input validation fails |
264
-
265
- ### Event Usage
266
-
267
- ```javascript
268
- const input = document.querySelector("#timepicker");
269
- const picker = new TimepickerUI(input);
270
- picker.create();
271
-
272
- // Listen to events
273
- input.addEventListener("timepicker:confirm", (e) => {
274
- console.log("Time confirmed:", e.detail);
275
- // e.detail contains: { hour, minutes, type, degreesHours, degreesMinutes }
276
- });
277
-
278
- input.addEventListener("timepicker:cancel", (e) => {
279
- console.log("Cancelled:", e.detail);
280
- });
281
-
282
- input.addEventListener("timepicker:error", (e) => {
283
- console.error("Error:", e.detail.error);
284
- });
285
- ```
286
-
287
- ---
288
-
289
- ## 🛠️ API Methods
182
+ ## API Methods
290
183
 
291
184
  ### Instance Methods
292
185
 
293
186
  ```javascript
294
187
  const picker = new TimepickerUI(input, options);
295
188
 
296
- // Core methods
297
- picker.create(); // Initialize the timepicker
298
- picker.open(); // Open the timepicker programmatically
299
- picker.close(); // Close the timepicker
300
- picker.destroy(); // Destroy instance and clean up
301
-
302
- // Value methods
303
- picker.getValue(); // Get current time value
304
- picker.setValue("14:30"); // Set time programmatically
305
-
306
- // Configuration methods
307
- picker.update({ options: newOptions }); // Update configuration
308
- picker.getElement(); // Get the DOM element
189
+ picker.create(); // Initialize
190
+ picker.open(); // Open programmatically
191
+ picker.close(); // Close
192
+ picker.destroy(); // Clean up
193
+ picker.getValue(); // Get current time
194
+ picker.setValue("14:30"); // Set time
195
+ picker.update({ options }); // Update configuration
309
196
  ```
310
197
 
311
198
  ### Static Methods
312
199
 
313
200
  ```javascript
314
- // Instance management
315
201
  TimepickerUI.getById("my-id"); // Get instance by ID
316
- TimepickerUI.getAllInstances(); // Get all active instances
202
+ TimepickerUI.getAllInstances(); // Get all instances
317
203
  TimepickerUI.destroyAll(); // Destroy all instances
318
- TimepickerUI.isAvailable(element); // Check if element exists
319
204
  ```
320
205
 
321
- ### Method Examples
322
-
323
- ```javascript
324
- // Get current value
325
- const currentTime = picker.getValue();
326
- console.log(currentTime);
327
- // Output: { hour: '14', minutes: '30', type: '', time: '14:30', degreesHours: 30, degreesMinutes: 180 }
328
-
329
- // Set new time
330
- picker.setValue("09:15 AM");
331
-
332
- // Update configuration
333
- picker.update({
334
- options: { theme: "dark", clockType: "24h" },
335
- create: true, // Reinitialize after update
336
- });
337
-
338
- // Instance management
339
- const picker1 = new TimepickerUI("#picker1", { id: "picker-1" });
340
- const picker2 = new TimepickerUI("#picker2", { id: "picker-2" });
341
-
342
- // Later...
343
- const foundPicker = TimepickerUI.getById("picker-1");
344
- ```
206
+ ## Events
345
207
 
346
- ---
208
+ Listen to timepicker events using the new **EventEmitter API** (recommended) or the legacy DOM events (deprecated, will be removed in v4):
347
209
 
348
- ## 🆕 What's New in v3.0
210
+ ### EventEmitter API (Recommended)
349
211
 
350
- ### ✅ New Features
212
+ ```javascript
213
+ const picker = new TimepickerUI(input);
214
+ picker.create();
351
215
 
352
- - **Inline Mode**: Always-visible timepicker without modal overlay
353
- - **Instance Management**: `getById()`, `destroyAll()`, and custom instance IDs
354
- - **Callback System**: Direct callback functions instead of manual event listeners
355
- - **New Themes**: Added `dark`, `glassmorphic`, `pastel`, `ai`, `cyberpunk`
356
- - **Enhanced API**: `getValue()`, `setValue()`, improved `destroy()`
357
- - **SSR Compatibility**: Better support for server-side rendering
358
- - **TypeScript Improvements**: Complete type definitions and better IntelliSense
216
+ picker.on("confirm", (data) => {
217
+ console.log("Time confirmed:", data);
218
+ });
359
219
 
360
- ### 🔄 Breaking Changes
220
+ picker.on("cancel", (data) => {
221
+ console.log("Cancelled:", data);
222
+ });
361
223
 
362
- - **Event Names**: All events now use `timepicker:` prefix
363
- - **Destroy Behavior**: `.destroy()` no longer removes input from DOM
364
- - **Theme Options**: Some theme names have changed
365
- - **API Changes**: Some method signatures have been updated
366
- - **Styles are no longer auto-loaded**
367
- You must now explicitly import CSS files. Use:
224
+ picker.on("open", () => {
225
+ console.log("Picker opened");
226
+ });
368
227
 
369
- - `main.css` core styles with `basic` theme only
370
- - `index.css` all styles including all themes
371
- - or import specific themes from `themes/`
228
+ picker.on("update", (data) => {
229
+ console.log("Time updated:", data);
230
+ });
372
231
 
373
- ---
232
+ picker.on("select:hour", (data) => {
233
+ console.log("Hour selected:", data.hour);
234
+ });
374
235
 
375
- ## 📈 Upgrade Guide: v2 v3
236
+ picker.on("select:minute", (data) => {
237
+ console.log("Minute selected:", data.minutes);
238
+ });
376
239
 
377
- ### 1. Update Event Listeners
240
+ picker.on("select:am", (data) => {
241
+ console.log("AM selected");
242
+ });
378
243
 
379
- **v2 (Old):**
244
+ picker.on("select:pm", (data) => {
245
+ console.log("PM selected");
246
+ });
380
247
 
381
- ```javascript
382
- input.addEventListener('show', (e) => { ... });
383
- input.addEventListener('cancel', (e) => { ... });
384
- input.addEventListener('accept', (e) => { ... });
385
- ```
248
+ picker.on("error", (data) => {
249
+ console.log("Error:", data.error);
250
+ });
386
251
 
387
- **v3 (New):**
252
+ picker.once("confirm", (data) => {
253
+ console.log("This runs only once");
254
+ });
388
255
 
389
- ```javascript
390
- input.addEventListener('timepicker:open', (e) => { ... });
391
- input.addEventListener('timepicker:cancel', (e) => { ... });
392
- input.addEventListener('timepicker:confirm', (e) => { ... });
256
+ picker.off("confirm", handler);
393
257
  ```
394
258
 
395
- ### 2. Replace Event Listeners with Callbacks
259
+ ### Legacy DOM Events (Deprecated)
396
260
 
397
- **v2 (Old):**
261
+ **Note:** DOM events (e.g., `timepicker:confirm`) are deprecated and will be removed in v4. Please migrate to the new EventEmitter API shown above.
398
262
 
399
263
  ```javascript
400
- const picker = new TimepickerUI(input);
401
- input.addEventListener("accept", (e) => {
402
- console.log("Time selected:", e.detail);
264
+ input.addEventListener("timepicker:confirm", (e) => {
265
+ console.log("Time:", e.detail);
403
266
  });
404
- ```
405
-
406
- **v3 (New):**
407
267
 
408
- ```javascript
409
- const picker = new TimepickerUI(input, {
410
- onConfirm: (data) => {
411
- console.log("Time selected:", data);
412
- },
268
+ input.addEventListener("timepicker:cancel", (e) => {
269
+ console.log("Cancelled");
413
270
  });
414
271
  ```
415
272
 
416
- ### 3. Update Destroy Method Usage
273
+ Available legacy events: `timepicker:open`, `timepicker:cancel`, `timepicker:confirm`, `timepicker:update`, `timepicker:select-hour`, `timepicker:select-minute`, `timepicker:select-am`, `timepicker:select-pm`, `timepicker:error`
417
274
 
418
- **v2 (Old):**
275
+ ## Upgrade Guide: v2 → v3
419
276
 
420
- ```javascript
421
- picker.destroy(); // This removed the input from DOM
422
- ```
277
+ ### Breaking Changes
423
278
 
424
- **v3 (New):**
279
+ **1. CSS must be imported manually**
425
280
 
426
281
  ```javascript
427
- picker.destroy(); // Only destroys timepicker, keeps input intact
428
- // If you need to remove input, do it manually:
429
- // input.remove();
282
+ // v3 - Required
283
+ import "timepicker-ui/main.css";
430
284
  ```
431
285
 
432
- ### 4. Theme Updates
433
-
434
- **v2 (Old):**
286
+ **2. Event names changed**
435
287
 
436
288
  ```javascript
437
- // Limited theme options
438
- theme: "basic" | "crane-straight" | "crane-radius" | "m3";
439
- ```
440
-
441
- **v3 (New):**
289
+ // v2
290
+ input.addEventListener("show", ...);
291
+ input.addEventListener("accept", ...);
442
292
 
443
- ```javascript
444
- // Extended theme options
445
- theme: "basic" |
446
- "crane-straight" |
447
- "crane-radius" |
448
- "m3" |
449
- "dark" |
450
- "glassmorphic" |
451
- "pastel" |
452
- "ai" |
453
- "cyberpunk";
293
+ // v3
294
+ input.addEventListener("timepicker:open", ...);
295
+ input.addEventListener("timepicker:confirm", ...);
454
296
  ```
455
297
 
456
- ### 5. Add Inline Mode (Optional)
457
-
458
- **v3 New Feature:**
298
+ **3. Use callbacks instead of events**
459
299
 
460
300
  ```javascript
301
+ // v3 - Recommended
461
302
  const picker = new TimepickerUI(input, {
462
- inline: {
463
- enabled: true,
464
- containerId: "timepicker-container",
465
- showButtons: false,
466
- autoUpdate: true,
467
- },
303
+ onConfirm: (data) => console.log(data),
304
+ onCancel: (data) => console.log("Cancelled"),
468
305
  });
469
306
  ```
470
307
 
471
- ### 6. Instance Management (Optional)
472
-
473
- **v3 New Feature:**
308
+ **4. destroy() behavior**
474
309
 
475
310
  ```javascript
476
- // Create with custom ID
477
- const picker = new TimepickerUI(input, { id: "my-timepicker" });
311
+ // v2 - Removed input from DOM
312
+ picker.destroy();
478
313
 
479
- // Later, get by ID
480
- const foundPicker = TimepickerUI.getById("my-timepicker");
481
-
482
- // Destroy all instances
483
- TimepickerUI.destroyAll();
314
+ // v3 - Only destroys picker, keeps input
315
+ picker.destroy();
484
316
  ```
485
317
 
486
- ### 7. Import CSS Manually (New Requirement)
487
-
488
- **v2 (Old):**
489
- Styles were bundled and automatically injected.
318
+ ### New in v3
490
319
 
491
- **v3 (New):**
492
- You must now import the styles yourself:
320
+ - Inline mode
321
+ - Instance management (`getById`, `destroyAll`)
322
+ - Direct callbacks
323
+ - 5 new themes
324
+ - `getValue()` and `setValue()` methods
325
+ - Better TypeScript support
326
+ - **EventEmitter API** for modern event handling (`on`, `off`, `once`)
493
327
 
494
- #### Option 1 All-in-one (includes every theme):
328
+ ### Migration to EventEmitter (v3.x)
495
329
 
496
- ```js
497
- import "timepicker-ui/index.css";
498
- ```
330
+ Starting in v3.x, we recommend using the new EventEmitter API instead of DOM events:
499
331
 
500
- #### Option 2 – Core only (main styles + basic theme):
332
+ ```javascript
333
+ // Old way (deprecated, will be removed in v4)
334
+ input.addEventListener("timepicker:confirm", (e) => {
335
+ console.log(e.detail);
336
+ });
501
337
 
502
- ```js
503
- import "timepicker-ui/main.css";
338
+ // New way (recommended)
339
+ picker.on("confirm", (data) => {
340
+ console.log(data);
341
+ });
504
342
  ```
505
343
 
506
- #### Option 3 – Use only the theme you need:
344
+ Benefits:
507
345
 
508
- ```js
509
- import "timepicker-ui/main.css"; // Required base
510
- import "timepicker-ui/theme-dark.css"; // Or any other theme
511
- ```
346
+ - Cleaner API without prefixes
347
+ - Better TypeScript support
348
+ - No DOM pollution
349
+ - Memory-efficient (automatic cleanup on destroy)
350
+ - Supports `once()` for one-time listeners
512
351
 
513
- ---
514
-
515
- ## 🌐 Framework Integration
352
+ ## Framework Integration
516
353
 
517
354
  ### React
518
355
 
519
- ```tsx
356
+ ```jsx
520
357
  import { useEffect, useRef } from "react";
521
358
  import { TimepickerUI } from "timepicker-ui";
359
+ import "timepicker-ui/main.css";
522
360
 
523
- function TimePicker({ onChange }) {
361
+ function App() {
524
362
  const inputRef = useRef(null);
525
- const pickerRef = useRef(null);
526
363
 
527
364
  useEffect(() => {
528
- if (inputRef.current) {
529
- pickerRef.current = new TimepickerUI(inputRef.current, {
530
- theme: "dark",
531
- onConfirm: (data) => {
532
- onChange?.(data);
533
- },
534
- });
535
- pickerRef.current.create();
536
- }
537
-
538
- return () => {
539
- pickerRef.current?.destroy();
540
- };
541
- }, [onChange]);
365
+ if (!inputRef.current) return;
366
+ const picker = new TimepickerUI(inputRef.current);
367
+ picker.create();
368
+ return () => picker.destroy();
369
+ }, []);
542
370
 
543
- return <input ref={inputRef} type="text" />;
371
+ return <input ref={inputRef} placeholder="Select time" />;
544
372
  }
545
373
  ```
546
374
 
@@ -548,105 +376,68 @@ function TimePicker({ onChange }) {
548
376
 
549
377
  ```vue
550
378
  <template>
551
- <input ref="inputRef" type="text" />
379
+ <input ref="pickerInput" placeholder="Select time" />
552
380
  </template>
553
381
 
554
382
  <script setup>
555
- import { ref, onMounted, onUnmounted } from "vue";
383
+ import { onMounted, ref } from "vue";
556
384
  import { TimepickerUI } from "timepicker-ui";
385
+ import "timepicker-ui/main.css";
557
386
 
558
- const inputRef = ref(null);
559
- let picker = null;
560
-
561
- const emit = defineEmits(["time-selected"]);
387
+ const pickerInput = ref(null);
562
388
 
563
389
  onMounted(() => {
564
- picker = new TimepickerUI(inputRef.value, {
565
- theme: "glassmorphic",
566
- onConfirm: (data) => {
567
- emit("time-selected", data);
568
- },
569
- });
390
+ if (!pickerInput.value) return;
391
+ const picker = new TimepickerUI(pickerInput.value);
570
392
  picker.create();
571
393
  });
572
-
573
- onUnmounted(() => {
574
- picker?.destroy();
575
- });
576
394
  </script>
577
395
  ```
578
396
 
579
397
  ### Angular
580
398
 
581
399
  ```typescript
582
- import {
583
- Component,
584
- ElementRef,
585
- ViewChild,
586
- AfterViewInit,
587
- OnDestroy,
588
- } from "@angular/core";
400
+ import { Component, ElementRef, ViewChild, AfterViewInit } from "@angular/core";
589
401
  import { TimepickerUI } from "timepicker-ui";
590
402
 
591
403
  @Component({
592
- selector: "app-timepicker",
593
- template: '<input #timepickerInput type="text" />',
404
+ selector: "app-root",
405
+ template: `<input #timepickerInput placeholder="Select time" />`,
594
406
  })
595
- export class TimepickerComponent implements AfterViewInit, OnDestroy {
596
- @ViewChild("timepickerInput") inputRef!: ElementRef;
597
- private picker!: TimepickerUI;
407
+ export class App implements AfterViewInit {
408
+ @ViewChild("timepickerInput") inputRef!: ElementRef<HTMLInputElement>;
598
409
 
599
410
  ngAfterViewInit() {
600
- this.picker = new TimepickerUI(this.inputRef.nativeElement, {
601
- theme: "ai",
602
- onConfirm: (data) => {
603
- console.log("Time selected:", data);
604
- },
605
- });
606
- this.picker.create();
607
- }
608
-
609
- ngOnDestroy() {
610
- this.picker?.destroy();
411
+ const picker = new TimepickerUI(this.inputRef.nativeElement);
412
+ picker.create();
611
413
  }
612
414
  }
613
415
  ```
614
416
 
615
- ---
417
+ Add to `angular.json` styles:
616
418
 
617
- ## 🔧 Development
419
+ ```json
420
+ "styles": ["src/styles.css", "timepicker-ui/main.css"]
421
+ ```
618
422
 
619
- All development and build tooling is located in the [`app/`](./app) directory.
620
- Please refer to [`app/README.md`](./app/README.md) for instructions on running the development server, building the library, running tests, and using the full toolchain.
423
+ ## Development
621
424
 
622
- ---
425
+ Development tooling is in the [`app/`](./app) directory. See [`app/README.md`](./app/README.md) for details.
623
426
 
624
- ## 📄 License
427
+ ## License
625
428
 
626
429
  MIT © [Piotr Glejzer](https://github.com/pglejzer)
627
430
 
628
- ---
629
-
630
- ## 🤝 Contributing
631
-
632
- Contributions, issues, and feature requests are welcome! Feel free to check the [issues page](https://github.com/pglejzer/timepicker-ui/issues).
633
-
634
- ---
431
+ ## Contributing
635
432
 
636
- ## 📊 Browser Support
433
+ Contributions welcome! Check the [issues page](https://github.com/pglejzer/timepicker-ui/issues).
637
434
 
638
- - Chrome 60+
639
- - Firefox 55+
640
- - Safari 12+
641
- - Edge 79+
642
- - iOS Safari 12+
643
- - Chrome Android 60+
435
+ ## Browser Support
644
436
 
645
- ---
437
+ Chrome 60+, Firefox 55+, Safari 12+, Edge 79+, iOS Safari 12+, Chrome Android 60+
646
438
 
647
- ## 🙋‍♂️ Support
439
+ ## Support
648
440
 
649
- - 📖 [Documentation](https://pglejzer.github.io/timepicker-ui-docs/)
650
- - 🐛 [Report Bug](https://github.com/pglejzer/timepicker-ui/issues)
651
- - 💡 [Request Feature](https://github.com/pglejzer/timepicker-ui/issues)
652
- - 💬 [Discussions](https://github.com/pglejzer/timepicker-ui/discussions)
441
+ - [Documentation](https://pglejzer.github.io/timepicker-ui-docs/)
442
+ - [Report Bug](https://github.com/pglejzer/timepicker-ui/issues)
443
+ - [Discussions](https://github.com/pglejzer/timepicker-ui/discussions)