timepicker-ui 4.2.2 → 4.3.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 +117 -805
- package/dist/index.cjs +2 -2
- package/dist/index.d.ts +7 -1
- package/dist/index.js +2 -2
- package/dist/index.umd.js +1 -1
- package/dist/plugins/range.cjs +1 -1
- package/dist/plugins/range.js +1 -1
- package/dist/plugins/range.umd.js +1 -1
- package/dist/plugins/timezone.cjs +1 -1
- package/dist/plugins/timezone.js +1 -1
- package/dist/plugins/timezone.umd.js +1 -1
- package/dist/plugins/wheel.cjs +1 -1
- package/dist/plugins/wheel.js +1 -1
- package/dist/plugins/wheel.umd.js +1 -1
- package/package.json +1 -3
package/README.md
CHANGED
|
@@ -1,87 +1,64 @@
|
|
|
1
1
|
# timepicker-ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Highly customizable time picker UI library for JavaScript and modern frameworks (React, Vue, Angular), with clock and wheel modes, zero dependencies, and full SSR support.
|
|
4
4
|
|
|
5
5
|
[](https://badge.fury.io/js/timepicker-ui)
|
|
6
6
|
[](https://npmcharts.com/compare/timepicker-ui?minimal=true)
|
|
7
7
|
[](https://img.shields.io/npm/l/timepicker-ui)
|
|
8
8
|
[](https://coveralls.io/github/pglejzer/timepicker-ui?branch=main)
|
|
9
9
|
[](https://github.com/pglejzer/timepicker-ui/actions/workflows/tests.yml)
|
|
10
|
-
[](https://badge.socket.dev/npm/package/timepicker-ui/4.3.0)
|
|
11
11
|
|
|
12
|
-
[Live Demo](https://timepicker-ui.vercel.app/) • [Documentation](https://timepicker-ui.vercel.app/docs) • [React Wrapper](https://github.com/pglejzer/timepicker-ui-react)
|
|
12
|
+
[Live Demo](https://timepicker-ui.vercel.app/) • [Documentation](https://timepicker-ui.vercel.app/docs) • [Changelog](./CHANGELOG.md) • [React Wrapper](https://github.com/pglejzer/timepicker-ui-react)
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
**Upgrading from v2?** Check the [v2 → v3 upgrade guide](#upgrade-guide-v2--v3).
|
|
14
|
+
## Why timepicker-ui?
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
23
|
-
- Framework agnostic - works with React, Vue, Angular, Svelte, or vanilla JS
|
|
24
|
-
- Full TypeScript support
|
|
25
|
-
- Inline mode for always-visible timepicker
|
|
26
|
-
- Clear button to reset time selection
|
|
27
|
-
- ARIA-compliant and keyboard accessible
|
|
28
|
-
- SSR compatible
|
|
29
|
-
- Lightweight with tree-shaking support
|
|
16
|
+
- **Zero dependencies** - no runtime deps, smaller bundle, no supply-chain risk
|
|
17
|
+
- **Multiple UI modes** - analog clock, scroll wheel, compact popover - not just one layout
|
|
18
|
+
- **Plugin architecture** - range, timezone, wheel - import only what you need
|
|
19
|
+
- **SSR safe** - works in Next.js, Nuxt, Remix, Astro out of the box
|
|
20
|
+
- **Any framework** - React, Vue, Angular, Svelte, or plain JS - same API everywhere
|
|
21
|
+
- **Accessible** - ARIA, keyboard nav, focus trap, screen reader support
|
|
30
22
|
|
|
31
|
-
##
|
|
23
|
+
## Use Cases
|
|
32
24
|
|
|
33
|
-
|
|
25
|
+
- Booking forms, scheduling, reservations
|
|
26
|
+
- Admin panels and dashboards
|
|
27
|
+
- Mobile-first apps with touch/scroll UX
|
|
28
|
+
- Time range selection (via Range plugin)
|
|
29
|
+
- SSR applications (Next.js, Nuxt, Remix, Astro)
|
|
34
30
|
|
|
35
|
-
|
|
36
|
-
import { TimepickerUI, PluginRegistry } from "timepicker-ui";
|
|
37
|
-
import { RangePlugin } from "timepicker-ui/plugins/range";
|
|
38
|
-
import { TimezonePlugin } from "timepicker-ui/plugins/timezone";
|
|
31
|
+
## Compared to Other Libraries
|
|
39
32
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
33
|
+
| | timepicker-ui | Typical UI lib |
|
|
34
|
+
| ----------------- | -------------------------------- | -------------------------- |
|
|
35
|
+
| Dependencies | **0** | 1-10+ |
|
|
36
|
+
| UI modes | Clock + Wheel + Compact | Clock only |
|
|
37
|
+
| Plugin system | Yes (range, timezone, wheel) | No |
|
|
38
|
+
| Framework lock-in | None - works everywhere | Often React-only |
|
|
39
|
+
| SSR safe | Yes, out of the box | Often requires workarounds |
|
|
40
|
+
| Tree-shakeable | Yes - plugins excluded if unused | Varies |
|
|
44
41
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
```javascript
|
|
48
|
-
import { TimepickerUI, PluginRegistry } from "timepicker-ui";
|
|
49
|
-
import { RangePlugin } from "timepicker-ui/plugins/range";
|
|
50
|
-
|
|
51
|
-
PluginRegistry.register(RangePlugin);
|
|
52
|
-
|
|
53
|
-
const picker = new TimepickerUI(input, {
|
|
54
|
-
range: { enabled: true },
|
|
55
|
-
});
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## Contributions
|
|
42
|
+
## Features
|
|
59
43
|
|
|
60
|
-
|
|
44
|
+
- [10 built-in themes](https://timepicker-ui.vercel.app/docs/features/themes) (Material, Crane, Dark, Glassmorphic, Cyberpunk, and more)
|
|
45
|
+
- [Analog clock](https://timepicker-ui.vercel.app/examples/basic/getting-started), [wheel](https://timepicker-ui.vercel.app/examples/plugins/wheel), and [compact-wheel](https://timepicker-ui.vercel.app/examples/plugins/wheel) picker modes
|
|
46
|
+
- [Inline mode](https://timepicker-ui.vercel.app/docs/features/inline-mode), [clear button](https://timepicker-ui.vercel.app/docs/features/clear-button), [disabled time ranges](https://timepicker-ui.vercel.app/docs/features/disabled-time)
|
|
47
|
+
- [Mobile-first](https://timepicker-ui.vercel.app/docs/features/mobile) with touch & keyboard support
|
|
48
|
+
- Framework agnostic - React, Vue, Angular, Svelte, vanilla JS
|
|
49
|
+
- Full [TypeScript support](https://timepicker-ui.vercel.app/docs/api/typescript), SSR compatible, true tree-shaking
|
|
61
50
|
|
|
62
51
|
## Installation
|
|
63
52
|
|
|
53
|
+
Full guide: [Installation docs](https://timepicker-ui.vercel.app/docs/installation)
|
|
54
|
+
|
|
64
55
|
```bash
|
|
65
56
|
npm install timepicker-ui
|
|
66
57
|
```
|
|
67
58
|
|
|
68
|
-
## Important: Global CSS Required
|
|
69
|
-
|
|
70
|
-
Your app needs this global CSS rule for correct styling:
|
|
71
|
-
|
|
72
|
-
```css
|
|
73
|
-
*,
|
|
74
|
-
*::before,
|
|
75
|
-
*::after {
|
|
76
|
-
box-sizing: border-box;
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Most projects include this by default.
|
|
81
|
-
|
|
82
59
|
## Quick Start
|
|
83
60
|
|
|
84
|
-
|
|
61
|
+
Full guide: [Quick Start docs](https://timepicker-ui.vercel.app/docs/quick-start)
|
|
85
62
|
|
|
86
63
|
```html
|
|
87
64
|
<input id="timepicker" type="text" />
|
|
@@ -92,819 +69,154 @@ import { TimepickerUI } from "timepicker-ui";
|
|
|
92
69
|
import "timepicker-ui/main.css";
|
|
93
70
|
|
|
94
71
|
const input = document.querySelector("#timepicker");
|
|
95
|
-
const picker = new TimepickerUI(input);
|
|
96
|
-
picker.create();
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
### With Options
|
|
100
|
-
|
|
101
|
-
```javascript
|
|
102
72
|
const picker = new TimepickerUI(input, {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
animation: true,
|
|
106
|
-
backdrop: true,
|
|
107
|
-
},
|
|
108
|
-
clock: {
|
|
109
|
-
type: "24h",
|
|
110
|
-
},
|
|
73
|
+
clock: { type: "24h" },
|
|
74
|
+
ui: { theme: "dark" },
|
|
111
75
|
callbacks: {
|
|
112
|
-
onConfirm: (data) =>
|
|
113
|
-
console.log("Selected time:", data);
|
|
114
|
-
},
|
|
76
|
+
onConfirm: (data) => console.log("Selected:", data),
|
|
115
77
|
},
|
|
116
78
|
});
|
|
117
79
|
picker.create();
|
|
118
80
|
```
|
|
119
81
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
```tsx
|
|
123
|
-
import { useEffect, useRef } from "react";
|
|
124
|
-
import { TimepickerUI } from "timepicker-ui";
|
|
125
|
-
import "timepicker-ui/main.css";
|
|
82
|
+
> **Note** - Requires [global](https://timepicker-ui.vercel.app/docs/installation) `box-sizing: border-box` (included by default in most frameworks) .
|
|
126
83
|
|
|
127
|
-
|
|
128
|
-
const inputRef = useRef<HTMLInputElement>(null);
|
|
84
|
+
## API
|
|
129
85
|
|
|
130
|
-
|
|
131
|
-
if (inputRef.current) {
|
|
132
|
-
const picker = new TimepickerUI(inputRef.current, {
|
|
133
|
-
callbacks: {
|
|
134
|
-
onConfirm: (data) => {
|
|
135
|
-
console.log("Time selected:", data);
|
|
136
|
-
},
|
|
137
|
-
});
|
|
138
|
-
picker.create();
|
|
139
|
-
|
|
140
|
-
return () => picker.destroy();
|
|
141
|
-
}
|
|
142
|
-
}, []);
|
|
143
|
-
|
|
144
|
-
return <input ref={inputRef} type="text" />;
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
## Configuration
|
|
149
|
-
|
|
150
|
-
Full documentation available at [timepicker-ui.vercel.app/docs](https://timepicker-ui.vercel.app/docs)
|
|
151
|
-
|
|
152
|
-
### Options Structure (v4.0.0 Breaking Change)
|
|
153
|
-
|
|
154
|
-
**Options are now organized into 5 logical groups:**
|
|
155
|
-
|
|
156
|
-
```typescript
|
|
157
|
-
const picker = new TimepickerUI(input, {
|
|
158
|
-
clock: ClockOptions, // Clock behavior (type, increments, disabled time)
|
|
159
|
-
ui: UIOptions, // Appearance (theme, animation, mobile, inline)
|
|
160
|
-
labels: LabelsOptions, // Text labels (AM/PM, buttons, headers)
|
|
161
|
-
behavior: BehaviorOptions, // Behavior (focus, delays, ID)
|
|
162
|
-
callbacks: CallbacksOptions, // Event handlers
|
|
163
|
-
clearBehavior: ClearBehaviorOptions, // Clear button behavior
|
|
164
|
-
wheel: WheelOptions, // Wheel/compact-wheel mode configuration
|
|
165
|
-
});
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### Clock Options
|
|
169
|
-
|
|
170
|
-
| Property | Type | Default | Description |
|
|
171
|
-
| --------------------- | -------------- | ----------- | ------------------------------- |
|
|
172
|
-
| `type` | `12h` / `24h` | `12h` | Clock format |
|
|
173
|
-
| `incrementHours` | number | `1` | Hour increment step |
|
|
174
|
-
| `incrementMinutes` | number | `1` | Minute increment step |
|
|
175
|
-
| `smoothHourSnap` | boolean | `true` | Smooth hour dragging with snap |
|
|
176
|
-
| `autoSwitchToMinutes` | boolean | `true` | Auto-switch after hour selected |
|
|
177
|
-
| `disabledTime` | object | `undefined` | Disable specific hours/minutes |
|
|
178
|
-
| `currentTime` | boolean/object | `undefined` | Set current time to input |
|
|
179
|
-
|
|
180
|
-
### UI Options
|
|
181
|
-
|
|
182
|
-
| Property | Type | Default | Description |
|
|
183
|
-
| --------------------- | ----------------------------------- | ----------- | ------------------------------------------------------------------ |
|
|
184
|
-
| `theme` | string | `basic` | Theme (11 themes available) |
|
|
185
|
-
| `animation` | boolean | `true` | Enable animations |
|
|
186
|
-
| `backdrop` | boolean | `true` | Show backdrop overlay |
|
|
187
|
-
| `mobile` | boolean | `false` | Force mobile version |
|
|
188
|
-
| `enableSwitchIcon` | boolean | `false` | Show desktop/mobile switch icon |
|
|
189
|
-
| `editable` | boolean | `false` | Allow manual input editing |
|
|
190
|
-
| `enableScrollbar` | boolean | `false` | Enable scroll when picker open |
|
|
191
|
-
| `cssClass` | string | `undefined` | Additional CSS class |
|
|
192
|
-
| `appendModalSelector` | string | `""` | Custom container selector |
|
|
193
|
-
| `iconTemplate` | string | SVG | Desktop switch icon template |
|
|
194
|
-
| `iconTemplateMobile` | string | SVG | Mobile switch icon template |
|
|
195
|
-
| `inline` | object | `undefined` | Inline mode configuration |
|
|
196
|
-
| `clearButton` | boolean | `false` | Show clear button |
|
|
197
|
-
| `mode` | `clock` / `wheel` / `compact-wheel` | `clock` | Picker mode - analog clock, scroll-spinner, or headerless wheel |
|
|
198
|
-
| `wheel` | `WheelOptions` | `undefined` | Wheel/compact-wheel config (placement, hideFooter, commitOnScroll) |
|
|
199
|
-
|
|
200
|
-
### Labels Options
|
|
201
|
-
|
|
202
|
-
| Property | Type | Default | Description |
|
|
203
|
-
| -------------- | ------ | ------------- | ------------------- |
|
|
204
|
-
| `am` | string | `AM` | AM label text |
|
|
205
|
-
| `pm` | string | `PM` | PM label text |
|
|
206
|
-
| `ok` | string | `OK` | OK button text |
|
|
207
|
-
| `cancel` | string | `Cancel` | Cancel button text |
|
|
208
|
-
| `time` | string | `Select time` | Desktop time label |
|
|
209
|
-
| `mobileTime` | string | `Enter Time` | Mobile time label |
|
|
210
|
-
| `mobileHour` | string | `Hour` | Mobile hour label |
|
|
211
|
-
| `mobileMinute` | string | `Minute` | Mobile minute label |
|
|
212
|
-
| `clear` | string | `Clear` | Clear button text |
|
|
213
|
-
|
|
214
|
-
### Behavior Options
|
|
215
|
-
|
|
216
|
-
| Property | Type | Default | Description |
|
|
217
|
-
| ---------------------- | ------- | -------------- | ----------------------- |
|
|
218
|
-
| `focusInputAfterClose` | boolean | `false` | Focus input after close |
|
|
219
|
-
| `focusTrap` | boolean | `true` | Trap focus in modal |
|
|
220
|
-
| `delayHandler` | number | `300` | Click delay (ms) |
|
|
221
|
-
| `id` | string | auto-generated | Custom instance ID |
|
|
222
|
-
|
|
223
|
-
### Clear Behavior Options
|
|
224
|
-
|
|
225
|
-
| Property | Type | Default | Description |
|
|
226
|
-
| ------------ | ------- | ------- | --------------------------------------- |
|
|
227
|
-
| `clearInput` | boolean | `true` | Whether clearing also empties the input |
|
|
228
|
-
|
|
229
|
-
### Wheel Options
|
|
230
|
-
|
|
231
|
-
| Property | Type | Default | Description |
|
|
232
|
-
| -------------------- | ------------------------- | ------- | -------------------------------------------------------------------- |
|
|
233
|
-
| `placement` | `auto` / `top` / `bottom` | `auto` | Popover placement in compact-wheel mode |
|
|
234
|
-
| `hideFooter` | boolean | `false` | Hide OK/Cancel/Clear buttons — useful with `commitOnScroll` |
|
|
235
|
-
| `commitOnScroll` | boolean | `false` | Auto-confirm time at end of scroll without pressing OK |
|
|
236
|
-
| `hideDisabled` | boolean | `false` | Remove disabled values from list instead of dimming them |
|
|
237
|
-
| `ignoreOutsideClick` | boolean | `false` | Prevent picker from closing when clicking outside (wheel modes only) |
|
|
238
|
-
|
|
239
|
-
### Callbacks Options
|
|
240
|
-
|
|
241
|
-
| Property | Type | Description |
|
|
242
|
-
| ---------------- | -------- | ------------------------ |
|
|
243
|
-
| `onConfirm` | function | Time confirmed |
|
|
244
|
-
| `onCancel` | function | Cancelled |
|
|
245
|
-
| `onOpen` | function | Picker opened |
|
|
246
|
-
| `onUpdate` | function | Time updated (real-time) |
|
|
247
|
-
| `onSelectHour` | function | Hour selected |
|
|
248
|
-
| `onSelectMinute` | function | Minute selected |
|
|
249
|
-
| `onSelectAM` | function | AM selected |
|
|
250
|
-
| `onSelectPM` | function | PM selected |
|
|
251
|
-
| `onError` | function | Error occurred |
|
|
252
|
-
| `onClear` | function | Time cleared |
|
|
253
|
-
|
|
254
|
-
### Migration from v3.x to v4.0.0
|
|
255
|
-
|
|
256
|
-
**All options must be moved into groups:**
|
|
257
|
-
|
|
258
|
-
```diff
|
|
259
|
-
// v3.x (DEPRECATED)
|
|
260
|
-
-const picker = new TimepickerUI(input, {
|
|
261
|
-
- clockType: '24h',
|
|
262
|
-
- theme: 'dark',
|
|
263
|
-
- animation: true,
|
|
264
|
-
- incrementMinutes: 5,
|
|
265
|
-
- amLabel: 'AM',
|
|
266
|
-
- onConfirm: (data) => {}
|
|
267
|
-
-});
|
|
268
|
-
|
|
269
|
-
// v4.0.0 (NEW)
|
|
270
|
-
+const picker = new TimepickerUI(input, {
|
|
271
|
-
+ clock: {
|
|
272
|
-
+ type: '24h',
|
|
273
|
-
+ incrementMinutes: 5
|
|
274
|
-
+ },
|
|
275
|
-
+ ui: {
|
|
276
|
-
+ theme: 'dark',
|
|
277
|
-
+ animation: true
|
|
278
|
-
+ },
|
|
279
|
-
+ labels: {
|
|
280
|
-
+ am: 'AM'
|
|
281
|
-
+ },
|
|
282
|
-
+ callbacks: {
|
|
283
|
-
+ onConfirm: (data) => {}
|
|
284
|
-
+ }
|
|
285
|
-
+});
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
**Full migration table:**
|
|
289
|
-
|
|
290
|
-
| v3.x (flat) | v4.0.0 (grouped) |
|
|
291
|
-
| --------------------------- | ------------------------------- |
|
|
292
|
-
| `clockType` | `clock.type` |
|
|
293
|
-
| `incrementHours` | `clock.incrementHours` |
|
|
294
|
-
| `incrementMinutes` | `clock.incrementMinutes` |
|
|
295
|
-
| `manualMinuteSwitch` | `clock.manualMinuteSwitch` |
|
|
296
|
-
| `disabledTime` | `clock.disabledTime` |
|
|
297
|
-
| `currentTime` | `clock.currentTime` |
|
|
298
|
-
| `theme` | `ui.theme` |
|
|
299
|
-
| `animation` | `ui.animation` |
|
|
300
|
-
| `backdrop` | `ui.backdrop` |
|
|
301
|
-
| `mobile` | `ui.mobile` |
|
|
302
|
-
| `enableSwitchIcon` | `ui.enableSwitchIcon` |
|
|
303
|
-
| `editable` | `ui.editable` |
|
|
304
|
-
| `enableScrollbar` | `ui.enableScrollbar` |
|
|
305
|
-
| `cssClass` | `ui.cssClass` |
|
|
306
|
-
| `appendModalSelector` | `ui.appendModalSelector` |
|
|
307
|
-
| `iconTemplate` | `ui.iconTemplate` |
|
|
308
|
-
| `iconTemplateMobile` | `ui.iconTemplateMobile` |
|
|
309
|
-
| `inline` | `ui.inline` |
|
|
310
|
-
| `amLabel` | `labels.am` |
|
|
311
|
-
| `pmLabel` | `labels.pm` |
|
|
312
|
-
| `okLabel` | `labels.ok` |
|
|
313
|
-
| `cancelLabel` | `labels.cancel` |
|
|
314
|
-
| `timeLabel` | `labels.time` |
|
|
315
|
-
| `mobileTimeLabel` | `labels.mobileTime` |
|
|
316
|
-
| `hourMobileLabel` | `labels.mobileHour` |
|
|
317
|
-
| `minuteMobileLabel` | `labels.mobileMinute` |
|
|
318
|
-
| `focusInputAfterCloseModal` | `behavior.focusInputAfterClose` |
|
|
319
|
-
| `focusTrap` | `behavior.focusTrap` |
|
|
320
|
-
| `delayHandler` | `behavior.delayHandler` |
|
|
321
|
-
| `id` | `behavior.id` |
|
|
322
|
-
| `onConfirm` | `callbacks.onConfirm` |
|
|
323
|
-
| `onCancel` | `callbacks.onCancel` |
|
|
324
|
-
| `onOpen` | `callbacks.onOpen` |
|
|
325
|
-
| `onUpdate` | `callbacks.onUpdate` |
|
|
326
|
-
| `onSelectHour` | `callbacks.onSelectHour` |
|
|
327
|
-
| `onSelectMinute` | `callbacks.onSelectMinute` |
|
|
328
|
-
| `onSelectAM` | `callbacks.onSelectAM` |
|
|
329
|
-
| `onSelectPM` | `callbacks.onSelectPM` |
|
|
330
|
-
| `onError` | `callbacks.onError` |
|
|
331
|
-
|
|
332
|
-
### Themes
|
|
333
|
-
|
|
334
|
-
Available themes: `basic`, `crane`, `crane-straight`, `m3-green`, `m2`, `dark`, `glassmorphic`, `pastel`, `ai`, `cyberpunk`
|
|
86
|
+
Full reference: [Methods](https://timepicker-ui.vercel.app/docs/api/methods) · [Events](https://timepicker-ui.vercel.app/docs/api/events) · [TypeScript](https://timepicker-ui.vercel.app/docs/api/typescript)
|
|
335
87
|
|
|
336
88
|
```javascript
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
});
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
### Disabled Time
|
|
348
|
-
|
|
349
|
-
```javascript
|
|
350
|
-
const picker = new TimepickerUI(input, {
|
|
351
|
-
clock: {
|
|
352
|
-
disabledTime: {
|
|
353
|
-
hours: [1, 3, 5, 8],
|
|
354
|
-
minutes: [15, 30, 45],
|
|
355
|
-
interval: "10:00 AM - 2:00 PM",
|
|
356
|
-
},
|
|
357
|
-
},
|
|
358
|
-
});
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
### Inline Mode
|
|
362
|
-
|
|
363
|
-
```javascript
|
|
364
|
-
const picker = new TimepickerUI(input, {
|
|
365
|
-
ui: {
|
|
366
|
-
inline: {
|
|
367
|
-
enabled: true,
|
|
368
|
-
containerId: "timepicker-container",
|
|
369
|
-
showButtons: false,
|
|
370
|
-
autoUpdate: true,
|
|
371
|
-
},
|
|
372
|
-
},
|
|
373
|
-
});
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
### Wheel Mode
|
|
377
|
-
|
|
378
|
-
Wheel mode replaces the analog clock face with a touch-friendly scroll-spinner. The header (hour/minute inputs, AM/PM toggle) and footer (OK/Cancel buttons) remain unchanged - only the clock body is replaced.
|
|
379
|
-
|
|
380
|
-
```javascript
|
|
381
|
-
const picker = new TimepickerUI(input, {
|
|
382
|
-
ui: { mode: "wheel" },
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
picker.create();
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
Wheel mode works with all existing features:
|
|
389
|
-
|
|
390
|
-
- **12h / 24h**: Respects `clock.type` - AM/PM column appears only in 12h mode
|
|
391
|
-
- **Themes**: Inherits the active theme via CSS variables
|
|
392
|
-
- **Disabled time**: Disabled hours/minutes are dimmed and skipped during scroll snap
|
|
393
|
-
- **Hide disabled options**: Set `wheel.hideDisabled: true` to completely remove disabled values from the list
|
|
394
|
-
- **setValue / getValue**: `picker.setValue('09:30 AM')` scrolls the wheel to the correct position
|
|
395
|
-
- **Keyboard navigation**: Arrow Up/Down scrolls one item, Tab moves between columns
|
|
396
|
-
- **Events**: All standard events work - `select:hour`, `select:minute`, `update`, `confirm`, `cancel`, `clear`, `select:am`, `select:pm`, `error`
|
|
397
|
-
- **Wheel-specific events**: `wheel:scroll:start` (column starts scrolling), `wheel:scroll:end` (column snaps to value with `previousValue`)
|
|
398
|
-
- **Auto-commit**: Set `wheel.commitOnScroll: true` to auto-confirm on scroll end without pressing OK
|
|
399
|
-
- **Persist on outside click**: Set `wheel.ignoreOutsideClick: true` to keep the picker open when clicking outside
|
|
400
|
-
|
|
401
|
-
### Compact-Wheel Mode
|
|
402
|
-
|
|
403
|
-
Compact-wheel mode is a headerless variant of wheel mode - it shows only the scroll wheels without the hour/minute input header. Ideal for minimal UIs or popover-style pickers.
|
|
404
|
-
|
|
405
|
-
```javascript
|
|
406
|
-
const picker = new TimepickerUI(input, {
|
|
407
|
-
ui: { mode: "compact-wheel" },
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
picker.create();
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
Combine with `wheel.placement` to open as a popover anchored to the input:
|
|
414
|
-
|
|
415
|
-
```javascript
|
|
416
|
-
const picker = new TimepickerUI(input, {
|
|
417
|
-
ui: { mode: "compact-wheel" },
|
|
418
|
-
wheel: {
|
|
419
|
-
placement: "auto", // 'auto', 'top', or 'bottom'
|
|
420
|
-
},
|
|
421
|
-
});
|
|
422
|
-
```
|
|
423
|
-
|
|
424
|
-
**Limitations:**
|
|
425
|
-
|
|
426
|
-
- Range plugin (`range.enabled`) is not supported in wheel or compact-wheel mode
|
|
427
|
-
- `ui.mobile` is ignored - wheel layout is always the same regardless of viewport
|
|
428
|
-
|
|
429
|
-
## API Methods
|
|
430
|
-
|
|
431
|
-
### Instance Methods
|
|
432
|
-
|
|
433
|
-
```javascript
|
|
434
|
-
const picker = new TimepickerUI(input, options);
|
|
435
|
-
|
|
436
|
-
picker.create(); // Initialize
|
|
437
|
-
picker.open(); // Open programmatically
|
|
438
|
-
picker.close(); // Close
|
|
439
|
-
picker.destroy(); // Clean up
|
|
440
|
-
picker.getValue(); // Get current time
|
|
441
|
-
picker.setValue("14:30"); // Set time
|
|
442
|
-
picker.update({ options }); // Update configuration
|
|
443
|
-
```
|
|
444
|
-
|
|
445
|
-
### Static Methods
|
|
446
|
-
|
|
447
|
-
```javascript
|
|
448
|
-
TimepickerUI.getById("my-id"); // Get instance by ID
|
|
449
|
-
TimepickerUI.getAllInstances(); // Get all instances
|
|
450
|
-
TimepickerUI.destroyAll(); // Destroy all instances
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
## Events
|
|
454
|
-
|
|
455
|
-
Listen to timepicker events using the **EventEmitter API** (v4+) or callback options:
|
|
456
|
-
|
|
457
|
-
### EventEmitter API (Recommended)
|
|
458
|
-
|
|
459
|
-
```javascript
|
|
460
|
-
const picker = new TimepickerUI(input);
|
|
461
|
-
picker.create();
|
|
462
|
-
|
|
463
|
-
picker.on("confirm", (data) => {
|
|
464
|
-
console.log("Time confirmed:", data);
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
picker.on("cancel", (data) => {
|
|
468
|
-
console.log("Cancelled:", data);
|
|
469
|
-
});
|
|
470
|
-
|
|
471
|
-
picker.on("open", () => {
|
|
472
|
-
console.log("Picker opened");
|
|
473
|
-
});
|
|
474
|
-
|
|
475
|
-
picker.on("update", (data) => {
|
|
476
|
-
console.log("Time updated:", data);
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
picker.on("select:hour", (data) => {
|
|
480
|
-
console.log("Hour selected:", data.hour);
|
|
481
|
-
});
|
|
482
|
-
|
|
483
|
-
picker.on("select:minute", (data) => {
|
|
484
|
-
console.log("Minute selected:", data.minutes);
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
picker.on("select:am", (data) => {
|
|
488
|
-
console.log("AM selected");
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
picker.on("select:pm", (data) => {
|
|
492
|
-
console.log("PM selected");
|
|
493
|
-
});
|
|
494
|
-
|
|
495
|
-
picker.on("error", (data) => {
|
|
496
|
-
console.log("Error:", data.error);
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
picker.on("clear", (data) => {
|
|
500
|
-
console.log("Cleared, previous value:", data.previousValue);
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
// Wheel-specific events (wheel mode only)
|
|
504
|
-
picker.on("wheel:scroll:start", (data) => {
|
|
505
|
-
console.log("Scroll started on:", data.column);
|
|
506
|
-
});
|
|
507
|
-
|
|
508
|
-
picker.on("wheel:scroll:end", (data) => {
|
|
509
|
-
console.log("Column:", data.column, "snapped to:", data.value);
|
|
510
|
-
console.log("Previous value:", data.previousValue);
|
|
511
|
-
});
|
|
512
|
-
|
|
513
|
-
picker.once("confirm", (data) => {
|
|
514
|
-
console.log("This runs only once");
|
|
515
|
-
});
|
|
89
|
+
picker.create(); // Initialize
|
|
90
|
+
picker.open(); // Open programmatically
|
|
91
|
+
picker.close(); // Close
|
|
92
|
+
picker.destroy(); // Clean up
|
|
93
|
+
picker.getValue(); // Get current time string
|
|
94
|
+
picker.setValue("14:30"); // Set time
|
|
95
|
+
picker.update({ ... }); // Update options at runtime
|
|
516
96
|
|
|
97
|
+
// Events
|
|
98
|
+
picker.on("confirm", (data) => {});
|
|
99
|
+
picker.on("cancel", (data) => {});
|
|
100
|
+
picker.on("open", () => {});
|
|
101
|
+
picker.on("update", (data) => {});
|
|
102
|
+
picker.on("clear", (data) => {});
|
|
103
|
+
picker.on("error", (data) => {});
|
|
104
|
+
picker.once("confirm", handler);
|
|
517
105
|
picker.off("confirm", handler);
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
### Legacy DOM Events (v3.x Only)
|
|
521
|
-
|
|
522
|
-
⚠️ **Only Available in v3.x - Completely Removed in v4.0.0**
|
|
523
106
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
```javascript
|
|
529
|
-
input.addEventListener("timepicker:confirm", (e) => {
|
|
530
|
-
console.log("Time:", e.detail);
|
|
531
|
-
});
|
|
107
|
+
// Static
|
|
108
|
+
TimepickerUI.getById("my-id");
|
|
109
|
+
TimepickerUI.getAllInstances();
|
|
110
|
+
TimepickerUI.destroyAll();
|
|
532
111
|
```
|
|
533
112
|
|
|
534
|
-
|
|
113
|
+
## Options Overview
|
|
535
114
|
|
|
536
|
-
|
|
537
|
-
// Option 1: EventEmitter API
|
|
538
|
-
picker.on("confirm", (data) => {
|
|
539
|
-
console.log("Time:", data);
|
|
540
|
-
});
|
|
115
|
+
Options are grouped into logical namespaces. Full reference: [Options docs](https://timepicker-ui.vercel.app/docs/api/options) · [Configuration guide](https://timepicker-ui.vercel.app/docs/configuration)
|
|
541
116
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
callbacks: {
|
|
545
|
-
onConfirm: (data) => {
|
|
546
|
-
console.log("Time:", data);
|
|
547
|
-
},
|
|
548
|
-
},
|
|
549
|
-
});
|
|
550
|
-
```
|
|
551
|
-
|
|
552
|
-
Removed events: `timepicker:open`, `timepicker:cancel`, `timepicker:confirm`, `timepicker:update`, `timepicker:select-hour`, `timepicker:select-minute`, `timepicker:select-am`, `timepicker:select-pm`, `timepicker:error`
|
|
553
|
-
|
|
554
|
-
## Upgrade Guide: v3 → v4
|
|
555
|
-
|
|
556
|
-
### Breaking Changes
|
|
557
|
-
|
|
558
|
-
**1. CSS Class Names Renamed**
|
|
559
|
-
|
|
560
|
-
All CSS classes have been shortened from `timepicker-ui-*` to `tp-ui-*`:
|
|
561
|
-
|
|
562
|
-
```css
|
|
563
|
-
/* v3 */
|
|
564
|
-
.timepicker-ui-wrapper {
|
|
565
|
-
}
|
|
566
|
-
.timepicker-ui-modal {
|
|
567
|
-
}
|
|
568
|
-
.timepicker-ui-clock-face {
|
|
569
|
-
}
|
|
570
|
-
.timepicker-ui-hour {
|
|
571
|
-
}
|
|
572
|
-
.timepicker-ui-minutes {
|
|
573
|
-
}
|
|
574
|
-
.timepicker-ui-am {
|
|
575
|
-
}
|
|
576
|
-
.timepicker-ui-pm {
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
/* v4 */
|
|
580
|
-
.tp-ui-wrapper {
|
|
581
|
-
}
|
|
582
|
-
.tp-ui-modal {
|
|
583
|
-
}
|
|
584
|
-
.tp-ui-clock-face {
|
|
585
|
-
}
|
|
586
|
-
.tp-ui-hour {
|
|
587
|
-
}
|
|
588
|
-
.tp-ui-minutes {
|
|
589
|
-
}
|
|
590
|
-
.tp-ui-am {
|
|
591
|
-
}
|
|
592
|
-
.tp-ui-pm {
|
|
593
|
-
}
|
|
594
|
-
```
|
|
595
|
-
|
|
596
|
-
**Impact:** If you have custom CSS targeting timepicker elements, update all class selectors.
|
|
597
|
-
|
|
598
|
-
**2. Grouped Options Structure**
|
|
599
|
-
|
|
600
|
-
All options are now organized into logical groups for better maintainability:
|
|
601
|
-
|
|
602
|
-
```javascript
|
|
603
|
-
// v3
|
|
604
|
-
const picker = new TimepickerUI(input, {
|
|
605
|
-
clockType: "12h",
|
|
606
|
-
theme: "dark",
|
|
607
|
-
enableSwitchIcon: true,
|
|
608
|
-
mobile: true,
|
|
609
|
-
animation: true,
|
|
610
|
-
backdrop: true,
|
|
611
|
-
focusTrap: true,
|
|
612
|
-
editable: true,
|
|
613
|
-
onConfirm: (data) => console.log(data),
|
|
614
|
-
});
|
|
615
|
-
|
|
616
|
-
// v4 - Grouped options
|
|
617
|
-
const picker = new TimepickerUI(input, {
|
|
117
|
+
```typescript
|
|
118
|
+
new TimepickerUI(input, {
|
|
618
119
|
clock: {
|
|
619
|
-
type: "12h",
|
|
120
|
+
type: "12h" | "24h", // default: "12h"
|
|
620
121
|
incrementHours: 1,
|
|
621
122
|
incrementMinutes: 1,
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
manualMinuteSwitch: false,
|
|
123
|
+
disabledTime: { hours: [], minutes: [], interval: "" },
|
|
124
|
+
currentTime: boolean | object,
|
|
625
125
|
},
|
|
626
126
|
ui: {
|
|
627
|
-
theme: "dark"
|
|
628
|
-
|
|
629
|
-
mobile: true,
|
|
127
|
+
theme: "basic" | "dark" | "m3-green" | "crane" | ..., // 10 themes
|
|
128
|
+
mode: "clock" | "wheel" | "compact-wheel", // default: "clock"
|
|
630
129
|
animation: true,
|
|
631
130
|
backdrop: true,
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
inline: { enabled: false },
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
time: "Select Time",
|
|
638
|
-
am: "AM",
|
|
639
|
-
pm: "PM",
|
|
640
|
-
ok: "OK",
|
|
641
|
-
cancel: "Cancel",
|
|
642
|
-
},
|
|
643
|
-
behavior: {
|
|
644
|
-
focusTrap: true,
|
|
645
|
-
focusInputAfterClose: false,
|
|
646
|
-
delayHandler: 300,
|
|
131
|
+
mobile: false,
|
|
132
|
+
editable: false,
|
|
133
|
+
inline: { enabled: false, containerId: "", showButtons: true, autoUpdate: false },
|
|
134
|
+
clearButton: false,
|
|
135
|
+
cssClass: "",
|
|
647
136
|
},
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
onUpdate: (data) => console.log(data),
|
|
653
|
-
onSelectHour: (data) => console.log(data),
|
|
654
|
-
onSelectMinute: (data) => console.log(data),
|
|
655
|
-
onSelectAM: (data) => console.log(data),
|
|
656
|
-
onSelectPM: (data) => console.log(data),
|
|
657
|
-
onError: (data) => console.log(data),
|
|
658
|
-
},
|
|
659
|
-
});
|
|
660
|
-
```
|
|
661
|
-
|
|
662
|
-
**2. Legacy DOM Events Removed**
|
|
663
|
-
|
|
664
|
-
DOM events have been completely removed. Use EventEmitter API or callback options:
|
|
665
|
-
|
|
666
|
-
```javascript
|
|
667
|
-
// v3 - Deprecated (removed in v4)
|
|
668
|
-
input.addEventListener("timepicker:confirm", (e) => {
|
|
669
|
-
console.log(e.detail);
|
|
670
|
-
});
|
|
671
|
-
|
|
672
|
-
// v4 - EventEmitter API (recommended)
|
|
673
|
-
picker.on("confirm", (data) => {
|
|
674
|
-
console.log(data);
|
|
675
|
-
});
|
|
676
|
-
|
|
677
|
-
// v4 - Or use callback options
|
|
678
|
-
const picker = new TimepickerUI(input, {
|
|
679
|
-
callbacks: {
|
|
680
|
-
onConfirm: (data) => console.log(data),
|
|
681
|
-
},
|
|
682
|
-
});
|
|
683
|
-
```
|
|
684
|
-
|
|
685
|
-
**3. setTheme() Method Removed**
|
|
686
|
-
|
|
687
|
-
Programmatic theme setting via `setTheme()` has been removed. Use CSS classes instead:
|
|
688
|
-
|
|
689
|
-
```javascript
|
|
690
|
-
// v3 - Removed in v4
|
|
691
|
-
picker.setTheme({
|
|
692
|
-
primaryColor: "#ff0000",
|
|
693
|
-
backgroundColor: "#000000",
|
|
694
|
-
});
|
|
695
|
-
|
|
696
|
-
// v4 - Use CSS classes with CSS variables
|
|
697
|
-
const picker = new TimepickerUI(input, {
|
|
698
|
-
ui: { cssClass: "my-custom-theme" },
|
|
137
|
+
labels: { am, pm, ok, cancel, time, mobileTime, mobileHour, mobileMinute, clear },
|
|
138
|
+
behavior: { focusTrap: true, focusInputAfterClose: false, delayHandler: 300, id: "" },
|
|
139
|
+
callbacks: { onConfirm, onCancel, onOpen, onUpdate, onSelectHour, onSelectMinute, onSelectAM, onSelectPM, onError, onClear },
|
|
140
|
+
wheel: { placement: "auto" | "top" | "bottom", hideFooter: false, commitOnScroll: false, hideDisabled: false, ignoreOutsideClick: false },
|
|
699
141
|
});
|
|
700
142
|
```
|
|
701
143
|
|
|
702
|
-
|
|
703
|
-
/* Define custom theme in CSS */
|
|
704
|
-
.tp-ui-wrapper.my-custom-theme {
|
|
705
|
-
--tp-primary: #ff0000;
|
|
706
|
-
--tp-bg: #000000;
|
|
707
|
-
--tp-surface: #f0f0f0;
|
|
708
|
-
}
|
|
709
|
-
```
|
|
710
|
-
|
|
711
|
-
**4. SSR-Safe Architecture**
|
|
712
|
-
|
|
713
|
-
All modules are now SSR-safe and can be imported in Node.js environments without crashing.
|
|
144
|
+
## Themes
|
|
714
145
|
|
|
715
|
-
|
|
146
|
+
Browse all themes: [Theme docs](https://timepicker-ui.vercel.app/docs/features/themes) · [Live examples](https://timepicker-ui.vercel.app/examples/themes/basic) · [Custom styling](https://timepicker-ui.vercel.app/docs/advanced/styling)
|
|
716
147
|
|
|
717
|
-
|
|
718
|
-
2. **Replace DOM events** - Switch to `picker.on()` EventEmitter API or callback options
|
|
719
|
-
3. **Remove setTheme() calls** - Use CSS classes with CSS variable overrides
|
|
720
|
-
4. **Test SSR compatibility** - If using Next.js/Nuxt/Remix, verify hydration works correctly
|
|
721
|
-
|
|
722
|
-
### New in v4
|
|
723
|
-
|
|
724
|
-
- **Composition-based architecture** - No inheritance, pure composition with managers
|
|
725
|
-
- **EventEmitter API** - Type-safe event handling with `on()`, `off()`, `once()`
|
|
726
|
-
- **Callback bridge** - Callbacks automatically connected to EventEmitter
|
|
727
|
-
- **SSR compatibility** - All modules can be imported in Node.js
|
|
728
|
-
- **Better TypeScript types** - Fully typed event payloads and options
|
|
729
|
-
- **Smaller bundle** - Removed unused code, optimized build (63.3 KB ESM)
|
|
730
|
-
- **Focus improvements** - Auto-focus on modal open, auto-focus on minute switch
|
|
731
|
-
- **Clear button** - Reset time selection with a dedicated clear button (v4.2.0)- **Compact-wheel mode** - Headerless wheel picker with optional popover placement (v4.2.0)
|
|
732
|
-
- **Hide disabled options** - Remove disabled values from the list instead of dimming (v4.2.0)
|
|
733
|
-
- **Auto-commit on scroll** - Auto-confirm time at scroll end in wheel modes (v4.2.0)
|
|
734
|
-
|
|
735
|
-
### Bundle Size Comparison
|
|
736
|
-
|
|
737
|
-
- v3: 80 KB ESM
|
|
738
|
-
- v4: 63.3 KB ESM (-20.9%)
|
|
739
|
-
|
|
740
|
-
---
|
|
741
|
-
|
|
742
|
-
## Upgrade Guide: v2 → v3
|
|
743
|
-
|
|
744
|
-
### Breaking Changes
|
|
745
|
-
|
|
746
|
-
**1. CSS must be imported manually**
|
|
148
|
+
Available: `basic`, `crane`, `crane-straight`, `m3-green`, `m2`, `dark`, `glassmorphic`, `pastel`, `ai`, `cyberpunk`
|
|
747
149
|
|
|
748
150
|
```javascript
|
|
749
|
-
//
|
|
750
|
-
import "timepicker-ui/
|
|
751
|
-
```
|
|
752
|
-
|
|
753
|
-
**2. Event names changed**
|
|
151
|
+
import "timepicker-ui/main.css"; // always required
|
|
152
|
+
import "timepicker-ui/theme-dark.css"; // theme-specific stylesheet
|
|
754
153
|
|
|
755
|
-
|
|
756
|
-
// v2
|
|
757
|
-
input.addEventListener("show", ...);
|
|
758
|
-
input.addEventListener("accept", ...);
|
|
759
|
-
|
|
760
|
-
// v3
|
|
761
|
-
input.addEventListener("timepicker:open", ...);
|
|
762
|
-
input.addEventListener("timepicker:confirm", ...);
|
|
154
|
+
new TimepickerUI(input, { ui: { theme: "dark" } });
|
|
763
155
|
```
|
|
764
156
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
```javascript
|
|
768
|
-
// v3 - Recommended
|
|
769
|
-
const picker = new TimepickerUI(input, {
|
|
770
|
-
onConfirm: (data) => console.log(data),
|
|
771
|
-
onCancel: (data) => console.log("Cancelled"),
|
|
772
|
-
});
|
|
773
|
-
```
|
|
157
|
+
## Plugins
|
|
774
158
|
|
|
775
|
-
|
|
159
|
+
Docs: [Plugins overview](https://timepicker-ui.vercel.app/docs/features/plugins) · Examples: [Range](https://timepicker-ui.vercel.app/examples/plugins/range) · [Timezone](https://timepicker-ui.vercel.app/examples/plugins/timezone) · [Wheel](https://timepicker-ui.vercel.app/examples/plugins/wheel)
|
|
776
160
|
|
|
777
161
|
```javascript
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
picker.destroy();
|
|
783
|
-
```
|
|
784
|
-
|
|
785
|
-
### New in v3
|
|
786
|
-
|
|
787
|
-
- Inline mode
|
|
788
|
-
- Instance management (`getById`, `destroyAll`)
|
|
789
|
-
- Direct callbacks
|
|
790
|
-
- 5 new themes
|
|
791
|
-
- `getValue()` and `setValue()` methods
|
|
792
|
-
- Better TypeScript support
|
|
793
|
-
- **EventEmitter API** for modern event handling (`on`, `off`, `once`)
|
|
794
|
-
|
|
795
|
-
### Migration to EventEmitter (v3.x)
|
|
796
|
-
|
|
797
|
-
Starting in v3.x, we recommend using the new EventEmitter API instead of DOM events:
|
|
162
|
+
import { TimepickerUI, PluginRegistry } from "timepicker-ui";
|
|
163
|
+
import { RangePlugin } from "timepicker-ui/plugins/range";
|
|
164
|
+
import { TimezonePlugin } from "timepicker-ui/plugins/timezone";
|
|
165
|
+
import { WheelPlugin } from "timepicker-ui/plugins/wheel";
|
|
798
166
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
});
|
|
167
|
+
// Register once at app startup
|
|
168
|
+
PluginRegistry.register(RangePlugin);
|
|
169
|
+
PluginRegistry.register(TimezonePlugin);
|
|
170
|
+
PluginRegistry.register(WheelPlugin);
|
|
804
171
|
|
|
805
|
-
|
|
806
|
-
picker.on("confirm", (data) => {
|
|
807
|
-
console.log(data);
|
|
808
|
-
});
|
|
172
|
+
new TimepickerUI(input, { range: { enabled: true } });
|
|
809
173
|
```
|
|
810
174
|
|
|
811
|
-
|
|
175
|
+
## Upgrading
|
|
812
176
|
|
|
813
|
-
-
|
|
814
|
-
-
|
|
815
|
-
- No DOM pollution
|
|
816
|
-
- Memory-efficient (automatic cleanup on destroy)
|
|
817
|
-
- Supports `once()` for one-time listeners
|
|
177
|
+
- **v3 → v4** - grouped options, EventEmitter API, CSS classes renamed. See [Migration Guide](https://timepicker-ui.vercel.app/docs/migration-guide) · [Breaking Changes](./readme/BREAKING_CHANGES_V4.md) · [CHANGELOG](./CHANGELOG.md)
|
|
178
|
+
- **v2 → v3** - CSS must be imported manually, event names changed. See [Legacy Migration](https://timepicker-ui.vercel.app/docs/legacy-migration) · [CHANGELOG](./CHANGELOG.md)
|
|
818
179
|
|
|
819
180
|
## Framework Integration
|
|
820
181
|
|
|
821
|
-
|
|
182
|
+
Full examples: [React](https://timepicker-ui.vercel.app/react) · [Vue / Angular / Svelte](https://timepicker-ui.vercel.app/docs/quick-start)
|
|
183
|
+
|
|
184
|
+
**React (quick example)**
|
|
822
185
|
|
|
823
|
-
```
|
|
186
|
+
```tsx
|
|
824
187
|
import { useEffect, useRef } from "react";
|
|
825
188
|
import { TimepickerUI } from "timepicker-ui";
|
|
826
189
|
import "timepicker-ui/main.css";
|
|
827
190
|
|
|
828
|
-
function
|
|
829
|
-
const
|
|
830
|
-
|
|
191
|
+
function TimePicker() {
|
|
192
|
+
const ref = useRef<HTMLInputElement>(null);
|
|
831
193
|
useEffect(() => {
|
|
832
|
-
if (!
|
|
833
|
-
const picker = new TimepickerUI(
|
|
194
|
+
if (!ref.current) return;
|
|
195
|
+
const picker = new TimepickerUI(ref.current);
|
|
834
196
|
picker.create();
|
|
835
197
|
return () => picker.destroy();
|
|
836
198
|
}, []);
|
|
837
|
-
|
|
838
|
-
return <input ref={inputRef} placeholder="Select time" />;
|
|
199
|
+
return <input ref={ref} />;
|
|
839
200
|
}
|
|
840
201
|
```
|
|
841
202
|
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
```vue
|
|
845
|
-
<template>
|
|
846
|
-
<input ref="pickerInput" placeholder="Select time" />
|
|
847
|
-
</template>
|
|
848
|
-
|
|
849
|
-
<script setup>
|
|
850
|
-
import { onMounted, ref } from "vue";
|
|
851
|
-
import { TimepickerUI } from "timepicker-ui";
|
|
852
|
-
import "timepicker-ui/main.css";
|
|
853
|
-
|
|
854
|
-
const pickerInput = ref(null);
|
|
855
|
-
|
|
856
|
-
onMounted(() => {
|
|
857
|
-
if (!pickerInput.value) return;
|
|
858
|
-
const picker = new TimepickerUI(pickerInput.value);
|
|
859
|
-
picker.create();
|
|
860
|
-
});
|
|
861
|
-
</script>
|
|
862
|
-
```
|
|
863
|
-
|
|
864
|
-
### Angular
|
|
865
|
-
|
|
866
|
-
```typescript
|
|
867
|
-
import { Component, ElementRef, ViewChild, AfterViewInit } from "@angular/core";
|
|
868
|
-
import { TimepickerUI } from "timepicker-ui";
|
|
869
|
-
|
|
870
|
-
@Component({
|
|
871
|
-
selector: "app-root",
|
|
872
|
-
template: `<input #timepickerInput placeholder="Select time" />`,
|
|
873
|
-
})
|
|
874
|
-
export class App implements AfterViewInit {
|
|
875
|
-
@ViewChild("timepickerInput") inputRef!: ElementRef<HTMLInputElement>;
|
|
876
|
-
|
|
877
|
-
ngAfterViewInit() {
|
|
878
|
-
const picker = new TimepickerUI(this.inputRef.nativeElement);
|
|
879
|
-
picker.create();
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
```
|
|
203
|
+
> There is also a dedicated [React wrapper package](https://github.com/pglejzer/timepicker-ui-react).
|
|
883
204
|
|
|
884
|
-
|
|
205
|
+
## Performance
|
|
885
206
|
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
207
|
+
- **Tree-shakeable** - unused plugins are fully excluded from the bundle
|
|
208
|
+
- **[Lightweight core](https://timepicker-ui.vercel.app/bundle-stats)** - with tree-shaking support
|
|
209
|
+
- **Plugins loaded on demand** - range, timezone, wheel add size only when imported
|
|
210
|
+
- **No runtime dependencies** - nothing extra to download or audit
|
|
889
211
|
|
|
890
212
|
## Development
|
|
891
213
|
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
## License
|
|
895
|
-
|
|
896
|
-
MIT © [Piotr Glejzer](https://github.com/pglejzer)
|
|
214
|
+
See [`app/README.md`](./app/README.md) for local development setup.
|
|
897
215
|
|
|
898
216
|
## Contributing
|
|
899
217
|
|
|
900
|
-
Contributions welcome!
|
|
218
|
+
Contributions welcome! [Open an issue or PR](https://github.com/pglejzer/timepicker-ui/issues).
|
|
901
219
|
|
|
902
|
-
##
|
|
903
|
-
|
|
904
|
-
Chrome 60+, Firefox 55+, Safari 12+, Edge 79+, iOS Safari 12+, Chrome Android 60+
|
|
905
|
-
|
|
906
|
-
## Support
|
|
220
|
+
## License
|
|
907
221
|
|
|
908
|
-
|
|
909
|
-
- [Report Bug](https://github.com/pglejzer/timepicker-ui/issues)
|
|
910
|
-
- [Discussions](https://github.com/pglejzer/timepicker-ui/discussions)
|
|
222
|
+
MIT © [Piotr Glejzer](https://github.com/pglejzer)
|