timepicker-ui 3.1.3 → 4.0.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/LICENSE +1 -1
- package/README.md +402 -56
- package/dist/css/index.css +1 -1
- package/dist/css/main.css +1 -1
- package/dist/css/themes/theme-ai.css +1 -1
- package/dist/css/themes/theme-crane-straight.css +1 -0
- package/dist/css/themes/theme-crane.css +1 -1
- package/dist/css/themes/theme-cyberpunk.css +1 -1
- package/dist/css/themes/theme-dark.css +1 -1
- package/dist/css/themes/theme-glassmorphic.css +1 -1
- package/dist/css/themes/theme-m2.css +1 -0
- package/dist/css/themes/theme-m3-green.css +1 -0
- package/dist/css/themes/theme-pastel.css +1 -1
- package/dist/index.cjs +1 -77
- package/dist/index.d.cts +439 -668
- package/dist/index.d.ts +439 -668
- package/dist/index.js +1 -77
- package/dist/index.umd.js +1 -1
- package/package.json +5 -5
- package/dist/css/themes/theme-custom.css +0 -1
- package/dist/css/themes/theme-m3.css +0 -1
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -8,11 +8,12 @@ Modern time picker library built with TypeScript. Works with any framework or va
|
|
|
8
8
|
|
|
9
9
|
[Live Demo](https://timepicker-ui.vercel.app/) • [Documentation](https://timepicker-ui.vercel.app/docs) • [Changelog](./CHANGELOG.md)
|
|
10
10
|
|
|
11
|
-
**Upgrading from
|
|
11
|
+
**Upgrading from v3?** Check the [upgrade guide](#upgrade-guide-v3--v4) below.
|
|
12
|
+
**Upgrading from v2?** Check the [v2 → v3 upgrade guide](#upgrade-guide-v2--v3).
|
|
12
13
|
|
|
13
14
|
## Features
|
|
14
15
|
|
|
15
|
-
-
|
|
16
|
+
- 10 built-in themes (Material, Crane, Dark, Glassmorphic, Cyberpunk, and more)
|
|
16
17
|
- Mobile-first design with touch support
|
|
17
18
|
- Framework agnostic - works with React, Vue, Angular, Svelte, or vanilla JS
|
|
18
19
|
- Full TypeScript support
|
|
@@ -25,10 +26,9 @@ Modern time picker library built with TypeScript. Works with any framework or va
|
|
|
25
26
|
|
|
26
27
|
This project is actively maintained. Some areas planned for improvement:
|
|
27
28
|
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
- No performance monitoring
|
|
29
|
+
- Unit/integration test coverage could be expanded
|
|
30
|
+
- Performance monitoring tooling
|
|
31
|
+
- Further TypeScript strictness improvements
|
|
32
32
|
|
|
33
33
|
Contributions welcome! Feel free to [open an issue or PR](https://github.com/pglejzer/timepicker-ui/issues).
|
|
34
34
|
|
|
@@ -73,12 +73,18 @@ picker.create();
|
|
|
73
73
|
|
|
74
74
|
```javascript
|
|
75
75
|
const picker = new TimepickerUI(input, {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
76
|
+
ui: {
|
|
77
|
+
theme: "dark",
|
|
78
|
+
animation: true,
|
|
79
|
+
backdrop: true,
|
|
80
|
+
},
|
|
81
|
+
clock: {
|
|
82
|
+
type: "24h",
|
|
83
|
+
},
|
|
84
|
+
callbacks: {
|
|
85
|
+
onConfirm: (data) => {
|
|
86
|
+
console.log("Selected time:", data);
|
|
87
|
+
},
|
|
82
88
|
},
|
|
83
89
|
});
|
|
84
90
|
picker.create();
|
|
@@ -97,8 +103,9 @@ function TimePickerComponent() {
|
|
|
97
103
|
useEffect(() => {
|
|
98
104
|
if (inputRef.current) {
|
|
99
105
|
const picker = new TimepickerUI(inputRef.current, {
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
callbacks: {
|
|
107
|
+
onConfirm: (data) => {
|
|
108
|
+
console.log("Time selected:", data);
|
|
102
109
|
},
|
|
103
110
|
});
|
|
104
111
|
picker.create();
|
|
@@ -115,42 +122,174 @@ function TimePickerComponent() {
|
|
|
115
122
|
|
|
116
123
|
Full documentation available at [timepicker-ui.vercel.app/docs](https://timepicker-ui.vercel.app/docs)
|
|
117
124
|
|
|
118
|
-
###
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
|
135
|
-
|
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
139
|
-
| `
|
|
140
|
-
| `
|
|
141
|
-
| `
|
|
142
|
-
|
|
125
|
+
### Options Structure (v4.0.0 Breaking Change)
|
|
126
|
+
|
|
127
|
+
**Options are now organized into 5 logical groups:**
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
const picker = new TimepickerUI(input, {
|
|
131
|
+
clock: ClockOptions, // Clock behavior (type, increments, disabled time)
|
|
132
|
+
ui: UIOptions, // Appearance (theme, animation, mobile, inline)
|
|
133
|
+
labels: LabelsOptions, // Text labels (AM/PM, buttons, headers)
|
|
134
|
+
behavior: BehaviorOptions, // Behavior (focus, delays, ID)
|
|
135
|
+
callbacks: CallbacksOptions, // Event handlers
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Clock Options
|
|
140
|
+
|
|
141
|
+
| Property | Type | Default | Description |
|
|
142
|
+
| --------------------- | -------------- | ----------- | ------------------------------- |
|
|
143
|
+
| `type` | `12h` / `24h` | `12h` | Clock format |
|
|
144
|
+
| `incrementHours` | number | `1` | Hour increment step |
|
|
145
|
+
| `incrementMinutes` | number | `1` | Minute increment step |
|
|
146
|
+
| `autoSwitchToMinutes` | boolean | `false` | Auto-switch after hour selected |
|
|
147
|
+
| `disabledTime` | object | `undefined` | Disable specific hours/minutes |
|
|
148
|
+
| `currentTime` | boolean/object | `undefined` | Set current time to input |
|
|
149
|
+
|
|
150
|
+
### UI Options
|
|
151
|
+
|
|
152
|
+
| Property | Type | Default | Description |
|
|
153
|
+
| --------------------- | ------- | ----------- | ------------------------------- |
|
|
154
|
+
| `theme` | string | `basic` | Theme (11 themes available) |
|
|
155
|
+
| `animation` | boolean | `true` | Enable animations |
|
|
156
|
+
| `backdrop` | boolean | `true` | Show backdrop overlay |
|
|
157
|
+
| `mobile` | boolean | `false` | Force mobile version |
|
|
158
|
+
| `enableSwitchIcon` | boolean | `false` | Show desktop/mobile switch icon |
|
|
159
|
+
| `editable` | boolean | `false` | Allow manual input editing |
|
|
160
|
+
| `enableScrollbar` | boolean | `false` | Enable scroll when picker open |
|
|
161
|
+
| `cssClass` | string | `undefined` | Additional CSS class |
|
|
162
|
+
| `appendModalSelector` | string | `""` | Custom container selector |
|
|
163
|
+
| `iconTemplate` | string | SVG | Desktop switch icon template |
|
|
164
|
+
| `iconTemplateMobile` | string | SVG | Mobile switch icon template |
|
|
165
|
+
| `inline` | object | `undefined` | Inline mode configuration |
|
|
166
|
+
|
|
167
|
+
### Labels Options
|
|
168
|
+
|
|
169
|
+
| Property | Type | Default | Description |
|
|
170
|
+
| -------------- | ------ | ------------- | ------------------- |
|
|
171
|
+
| `am` | string | `AM` | AM label text |
|
|
172
|
+
| `pm` | string | `PM` | PM label text |
|
|
173
|
+
| `ok` | string | `OK` | OK button text |
|
|
174
|
+
| `cancel` | string | `Cancel` | Cancel button text |
|
|
175
|
+
| `time` | string | `Select time` | Desktop time label |
|
|
176
|
+
| `mobileTime` | string | `Enter Time` | Mobile time label |
|
|
177
|
+
| `mobileHour` | string | `Hour` | Mobile hour label |
|
|
178
|
+
| `mobileMinute` | string | `Minute` | Mobile minute label |
|
|
179
|
+
|
|
180
|
+
### Behavior Options
|
|
181
|
+
|
|
182
|
+
| Property | Type | Default | Description |
|
|
183
|
+
| ---------------------- | ------- | -------------- | ----------------------- |
|
|
184
|
+
| `focusInputAfterClose` | boolean | `false` | Focus input after close |
|
|
185
|
+
| `focusTrap` | boolean | `true` | Trap focus in modal |
|
|
186
|
+
| `delayHandler` | number | `300` | Click delay (ms) |
|
|
187
|
+
| `id` | string | auto-generated | Custom instance ID |
|
|
188
|
+
|
|
189
|
+
### Callbacks Options
|
|
190
|
+
|
|
191
|
+
| Property | Type | Description |
|
|
192
|
+
| ---------------- | -------- | ------------------------ |
|
|
193
|
+
| `onConfirm` | function | Time confirmed |
|
|
194
|
+
| `onCancel` | function | Cancelled |
|
|
195
|
+
| `onOpen` | function | Picker opened |
|
|
196
|
+
| `onUpdate` | function | Time updated (real-time) |
|
|
197
|
+
| `onSelectHour` | function | Hour selected |
|
|
198
|
+
| `onSelectMinute` | function | Minute selected |
|
|
199
|
+
| `onSelectAM` | function | AM selected |
|
|
200
|
+
| `onSelectPM` | function | PM selected |
|
|
201
|
+
| `onError` | function | Error occurred |
|
|
202
|
+
|
|
203
|
+
### Migration from v3.x to v4.0.0
|
|
204
|
+
|
|
205
|
+
**All options must be moved into groups:**
|
|
206
|
+
|
|
207
|
+
```diff
|
|
208
|
+
// v3.x (DEPRECATED)
|
|
209
|
+
-const picker = new TimepickerUI(input, {
|
|
210
|
+
- clockType: '24h',
|
|
211
|
+
- theme: 'dark',
|
|
212
|
+
- animation: true,
|
|
213
|
+
- incrementMinutes: 5,
|
|
214
|
+
- amLabel: 'AM',
|
|
215
|
+
- onConfirm: (data) => {}
|
|
216
|
+
-});
|
|
217
|
+
|
|
218
|
+
// v4.0.0 (NEW)
|
|
219
|
+
+const picker = new TimepickerUI(input, {
|
|
220
|
+
+ clock: {
|
|
221
|
+
+ type: '24h',
|
|
222
|
+
+ incrementMinutes: 5
|
|
223
|
+
+ },
|
|
224
|
+
+ ui: {
|
|
225
|
+
+ theme: 'dark',
|
|
226
|
+
+ animation: true
|
|
227
|
+
+ },
|
|
228
|
+
+ labels: {
|
|
229
|
+
+ am: 'AM'
|
|
230
|
+
+ },
|
|
231
|
+
+ callbacks: {
|
|
232
|
+
+ onConfirm: (data) => {}
|
|
233
|
+
+ }
|
|
234
|
+
+});
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Full migration table:**
|
|
238
|
+
|
|
239
|
+
| v3.x (flat) | v4.0.0 (grouped) |
|
|
240
|
+
| --------------------------- | ------------------------------- |
|
|
241
|
+
| `clockType` | `clock.type` |
|
|
242
|
+
| `incrementHours` | `clock.incrementHours` |
|
|
243
|
+
| `incrementMinutes` | `clock.incrementMinutes` |
|
|
244
|
+
| `autoSwitchToMinutes` | `clock.autoSwitchToMinutes` |
|
|
245
|
+
| `disabledTime` | `clock.disabledTime` |
|
|
246
|
+
| `currentTime` | `clock.currentTime` |
|
|
247
|
+
| `theme` | `ui.theme` |
|
|
248
|
+
| `animation` | `ui.animation` |
|
|
249
|
+
| `backdrop` | `ui.backdrop` |
|
|
250
|
+
| `mobile` | `ui.mobile` |
|
|
251
|
+
| `enableSwitchIcon` | `ui.enableSwitchIcon` |
|
|
252
|
+
| `editable` | `ui.editable` |
|
|
253
|
+
| `enableScrollbar` | `ui.enableScrollbar` |
|
|
254
|
+
| `cssClass` | `ui.cssClass` |
|
|
255
|
+
| `appendModalSelector` | `ui.appendModalSelector` |
|
|
256
|
+
| `iconTemplate` | `ui.iconTemplate` |
|
|
257
|
+
| `iconTemplateMobile` | `ui.iconTemplateMobile` |
|
|
258
|
+
| `inline` | `ui.inline` |
|
|
259
|
+
| `amLabel` | `labels.am` |
|
|
260
|
+
| `pmLabel` | `labels.pm` |
|
|
261
|
+
| `okLabel` | `labels.ok` |
|
|
262
|
+
| `cancelLabel` | `labels.cancel` |
|
|
263
|
+
| `timeLabel` | `labels.time` |
|
|
264
|
+
| `mobileTimeLabel` | `labels.mobileTime` |
|
|
265
|
+
| `hourMobileLabel` | `labels.mobileHour` |
|
|
266
|
+
| `minuteMobileLabel` | `labels.mobileMinute` |
|
|
267
|
+
| `focusInputAfterCloseModal` | `behavior.focusInputAfterClose` |
|
|
268
|
+
| `focusTrap` | `behavior.focusTrap` |
|
|
269
|
+
| `delayHandler` | `behavior.delayHandler` |
|
|
270
|
+
| `id` | `behavior.id` |
|
|
271
|
+
| `onConfirm` | `callbacks.onConfirm` |
|
|
272
|
+
| `onCancel` | `callbacks.onCancel` |
|
|
273
|
+
| `onOpen` | `callbacks.onOpen` |
|
|
274
|
+
| `onUpdate` | `callbacks.onUpdate` |
|
|
275
|
+
| `onSelectHour` | `callbacks.onSelectHour` |
|
|
276
|
+
| `onSelectMinute` | `callbacks.onSelectMinute` |
|
|
277
|
+
| `onSelectAM` | `callbacks.onSelectAM` |
|
|
278
|
+
| `onSelectPM` | `callbacks.onSelectPM` |
|
|
279
|
+
| `onError` | `callbacks.onError` |
|
|
143
280
|
|
|
144
281
|
### Themes
|
|
145
282
|
|
|
146
|
-
Available themes: `basic`, `crane
|
|
283
|
+
Available themes: `basic`, `crane`, `crane-straight`, `m3-green`, `m2`, `dark`, `glassmorphic`, `pastel`, `ai`, `cyberpunk`
|
|
147
284
|
|
|
148
285
|
```javascript
|
|
149
286
|
import "timepicker-ui/main.css"; // Required base styles
|
|
150
287
|
import "timepicker-ui/theme-dark.css"; // Specific theme
|
|
151
288
|
|
|
152
289
|
const picker = new TimepickerUI(input, {
|
|
153
|
-
|
|
290
|
+
ui: {
|
|
291
|
+
theme: "dark",
|
|
292
|
+
},
|
|
154
293
|
});
|
|
155
294
|
```
|
|
156
295
|
|
|
@@ -158,10 +297,12 @@ const picker = new TimepickerUI(input, {
|
|
|
158
297
|
|
|
159
298
|
```javascript
|
|
160
299
|
const picker = new TimepickerUI(input, {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
300
|
+
clock: {
|
|
301
|
+
disabledTime: {
|
|
302
|
+
hours: [1, 3, 5, 8],
|
|
303
|
+
minutes: [15, 30, 45],
|
|
304
|
+
interval: "10:00 AM - 2:00 PM",
|
|
305
|
+
},
|
|
165
306
|
},
|
|
166
307
|
});
|
|
167
308
|
```
|
|
@@ -170,11 +311,13 @@ const picker = new TimepickerUI(input, {
|
|
|
170
311
|
|
|
171
312
|
```javascript
|
|
172
313
|
const picker = new TimepickerUI(input, {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
314
|
+
ui: {
|
|
315
|
+
inline: {
|
|
316
|
+
enabled: true,
|
|
317
|
+
containerId: "timepicker-container",
|
|
318
|
+
showButtons: false,
|
|
319
|
+
autoUpdate: true,
|
|
320
|
+
},
|
|
178
321
|
},
|
|
179
322
|
});
|
|
180
323
|
```
|
|
@@ -205,7 +348,7 @@ TimepickerUI.destroyAll(); // Destroy all instances
|
|
|
205
348
|
|
|
206
349
|
## Events
|
|
207
350
|
|
|
208
|
-
Listen to timepicker events using the
|
|
351
|
+
Listen to timepicker events using the **EventEmitter API** (v4+) or callback options:
|
|
209
352
|
|
|
210
353
|
### EventEmitter API (Recommended)
|
|
211
354
|
|
|
@@ -256,21 +399,224 @@ picker.once("confirm", (data) => {
|
|
|
256
399
|
picker.off("confirm", handler);
|
|
257
400
|
```
|
|
258
401
|
|
|
259
|
-
### Legacy DOM Events (
|
|
402
|
+
### Legacy DOM Events (v3.x Only)
|
|
403
|
+
|
|
404
|
+
⚠️ **Only Available in v3.x - Completely Removed in v4.0.0**
|
|
405
|
+
|
|
406
|
+
DOM events (e.g., `timepicker:confirm`) were removed in v4.0.0. Use the **EventEmitter API** shown above or **callback options** instead.
|
|
260
407
|
|
|
261
|
-
**
|
|
408
|
+
**v3.x code (no longer works in v4):**
|
|
262
409
|
|
|
263
410
|
```javascript
|
|
264
411
|
input.addEventListener("timepicker:confirm", (e) => {
|
|
265
412
|
console.log("Time:", e.detail);
|
|
266
413
|
});
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
**v4.0.0 alternatives:**
|
|
417
|
+
|
|
418
|
+
```javascript
|
|
419
|
+
// Option 1: EventEmitter API
|
|
420
|
+
picker.on("confirm", (data) => {
|
|
421
|
+
console.log("Time:", data);
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Option 2: Callback options
|
|
425
|
+
const picker = new TimepickerUI(input, {
|
|
426
|
+
callbacks: {
|
|
427
|
+
onConfirm: (data) => {
|
|
428
|
+
console.log("Time:", data);
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
});
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
Removed events: `timepicker:open`, `timepicker:cancel`, `timepicker:confirm`, `timepicker:update`, `timepicker:select-hour`, `timepicker:select-minute`, `timepicker:select-am`, `timepicker:select-pm`, `timepicker:error`
|
|
435
|
+
|
|
436
|
+
## Upgrade Guide: v3 → v4
|
|
437
|
+
|
|
438
|
+
### Breaking Changes
|
|
439
|
+
|
|
440
|
+
**1. CSS Class Names Renamed**
|
|
441
|
+
|
|
442
|
+
All CSS classes have been shortened from `timepicker-ui-*` to `tp-ui-*`:
|
|
443
|
+
|
|
444
|
+
```css
|
|
445
|
+
/* v3 */
|
|
446
|
+
.timepicker-ui-wrapper {
|
|
447
|
+
}
|
|
448
|
+
.timepicker-ui-modal {
|
|
449
|
+
}
|
|
450
|
+
.timepicker-ui-clock-face {
|
|
451
|
+
}
|
|
452
|
+
.timepicker-ui-hour {
|
|
453
|
+
}
|
|
454
|
+
.timepicker-ui-minutes {
|
|
455
|
+
}
|
|
456
|
+
.timepicker-ui-am {
|
|
457
|
+
}
|
|
458
|
+
.timepicker-ui-pm {
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/* v4 */
|
|
462
|
+
.tp-ui-wrapper {
|
|
463
|
+
}
|
|
464
|
+
.tp-ui-modal {
|
|
465
|
+
}
|
|
466
|
+
.tp-ui-clock-face {
|
|
467
|
+
}
|
|
468
|
+
.tp-ui-hour {
|
|
469
|
+
}
|
|
470
|
+
.tp-ui-minutes {
|
|
471
|
+
}
|
|
472
|
+
.tp-ui-am {
|
|
473
|
+
}
|
|
474
|
+
.tp-ui-pm {
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
**Impact:** If you have custom CSS targeting timepicker elements, update all class selectors.
|
|
479
|
+
|
|
480
|
+
**2. Grouped Options Structure**
|
|
481
|
+
|
|
482
|
+
All options are now organized into logical groups for better maintainability:
|
|
483
|
+
|
|
484
|
+
```javascript
|
|
485
|
+
// v3
|
|
486
|
+
const picker = new TimepickerUI(input, {
|
|
487
|
+
clockType: "12h",
|
|
488
|
+
theme: "dark",
|
|
489
|
+
enableSwitchIcon: true,
|
|
490
|
+
mobile: true,
|
|
491
|
+
animation: true,
|
|
492
|
+
backdrop: true,
|
|
493
|
+
focusTrap: true,
|
|
494
|
+
editable: true,
|
|
495
|
+
onConfirm: (data) => console.log(data),
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
// v4 - Grouped options
|
|
499
|
+
const picker = new TimepickerUI(input, {
|
|
500
|
+
clock: {
|
|
501
|
+
type: "12h",
|
|
502
|
+
incrementHours: 1,
|
|
503
|
+
incrementMinutes: 1,
|
|
504
|
+
currentTime: { time: new Date(), updateInput: true },
|
|
505
|
+
disabledTime: { hours: [1, 2, 3] },
|
|
506
|
+
autoSwitchToMinutes: false,
|
|
507
|
+
},
|
|
508
|
+
ui: {
|
|
509
|
+
theme: "dark",
|
|
510
|
+
enableSwitchIcon: true,
|
|
511
|
+
mobile: true,
|
|
512
|
+
animation: true,
|
|
513
|
+
backdrop: true,
|
|
514
|
+
editable: true,
|
|
515
|
+
cssClass: "my-custom-class",
|
|
516
|
+
inline: { enabled: false },
|
|
517
|
+
},
|
|
518
|
+
labels: {
|
|
519
|
+
time: "Select Time",
|
|
520
|
+
am: "AM",
|
|
521
|
+
pm: "PM",
|
|
522
|
+
ok: "OK",
|
|
523
|
+
cancel: "Cancel",
|
|
524
|
+
},
|
|
525
|
+
behavior: {
|
|
526
|
+
focusTrap: true,
|
|
527
|
+
focusInputAfterClose: false,
|
|
528
|
+
delayHandler: 300,
|
|
529
|
+
},
|
|
530
|
+
callbacks: {
|
|
531
|
+
onConfirm: (data) => console.log(data),
|
|
532
|
+
onCancel: (data) => console.log(data),
|
|
533
|
+
onOpen: (data) => console.log(data),
|
|
534
|
+
onUpdate: (data) => console.log(data),
|
|
535
|
+
onSelectHour: (data) => console.log(data),
|
|
536
|
+
onSelectMinute: (data) => console.log(data),
|
|
537
|
+
onSelectAM: (data) => console.log(data),
|
|
538
|
+
onSelectPM: (data) => console.log(data),
|
|
539
|
+
onError: (data) => console.log(data),
|
|
540
|
+
},
|
|
541
|
+
});
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
**2. Legacy DOM Events Removed**
|
|
545
|
+
|
|
546
|
+
DOM events have been completely removed. Use EventEmitter API or callback options:
|
|
547
|
+
|
|
548
|
+
```javascript
|
|
549
|
+
// v3 - Deprecated (removed in v4)
|
|
550
|
+
input.addEventListener("timepicker:confirm", (e) => {
|
|
551
|
+
console.log(e.detail);
|
|
552
|
+
});
|
|
267
553
|
|
|
268
|
-
|
|
269
|
-
|
|
554
|
+
// v4 - EventEmitter API (recommended)
|
|
555
|
+
picker.on("confirm", (data) => {
|
|
556
|
+
console.log(data);
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
// v4 - Or use callback options
|
|
560
|
+
const picker = new TimepickerUI(input, {
|
|
561
|
+
callbacks: {
|
|
562
|
+
onConfirm: (data) => console.log(data),
|
|
563
|
+
},
|
|
270
564
|
});
|
|
271
565
|
```
|
|
272
566
|
|
|
273
|
-
|
|
567
|
+
**3. setTheme() Method Removed**
|
|
568
|
+
|
|
569
|
+
Programmatic theme setting via `setTheme()` has been removed. Use CSS classes instead:
|
|
570
|
+
|
|
571
|
+
```javascript
|
|
572
|
+
// v3 - Removed in v4
|
|
573
|
+
picker.setTheme({
|
|
574
|
+
primaryColor: "#ff0000",
|
|
575
|
+
backgroundColor: "#000000",
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
// v4 - Use CSS classes with CSS variables
|
|
579
|
+
const picker = new TimepickerUI(input, {
|
|
580
|
+
ui: { cssClass: "my-custom-theme" },
|
|
581
|
+
});
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
```css
|
|
585
|
+
/* Define custom theme in CSS */
|
|
586
|
+
.tp-ui-wrapper.my-custom-theme {
|
|
587
|
+
--tp-primary: #ff0000;
|
|
588
|
+
--tp-bg: #000000;
|
|
589
|
+
--tp-surface: #f0f0f0;
|
|
590
|
+
}
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
**4. SSR-Safe Architecture**
|
|
594
|
+
|
|
595
|
+
All modules are now SSR-safe and can be imported in Node.js environments without crashing.
|
|
596
|
+
|
|
597
|
+
### Migration Steps
|
|
598
|
+
|
|
599
|
+
1. **Update option structure** - Move options into `clock`, `ui`, `labels`, `behavior`, `callbacks` groups
|
|
600
|
+
2. **Replace DOM events** - Switch to `picker.on()` EventEmitter API or callback options
|
|
601
|
+
3. **Remove setTheme() calls** - Use CSS classes with CSS variable overrides
|
|
602
|
+
4. **Test SSR compatibility** - If using Next.js/Nuxt/Remix, verify hydration works correctly
|
|
603
|
+
|
|
604
|
+
### New in v4
|
|
605
|
+
|
|
606
|
+
- **Composition-based architecture** - No inheritance, pure composition with managers
|
|
607
|
+
- **EventEmitter API** - Type-safe event handling with `on()`, `off()`, `once()`
|
|
608
|
+
- **Callback bridge** - Callbacks automatically connected to EventEmitter
|
|
609
|
+
- **SSR compatibility** - All modules can be imported in Node.js
|
|
610
|
+
- **Better TypeScript types** - Fully typed event payloads and options
|
|
611
|
+
- **Smaller bundle** - Removed unused code, optimized build (63.3 KB ESM)
|
|
612
|
+
- **Focus improvements** - Auto-focus on modal open, auto-focus on minute switch
|
|
613
|
+
|
|
614
|
+
### Bundle Size Comparison
|
|
615
|
+
|
|
616
|
+
- v3: 80 KB ESM
|
|
617
|
+
- v4: 63.3 KB ESM (-20.9%)
|
|
618
|
+
|
|
619
|
+
---
|
|
274
620
|
|
|
275
621
|
## Upgrade Guide: v2 → v3
|
|
276
622
|
|