cupertino-datetime-picker 0.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/LICENSE +21 -0
- package/README.md +114 -0
- package/dist/calendar-panel.d.ts +27 -0
- package/dist/calendar.d.ts +33 -0
- package/dist/date-time-picker.d.ts +31 -0
- package/dist/hooks.d.ts +3 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +832 -0
- package/dist/index.js.map +1 -0
- package/dist/segmented-control.d.ts +17 -0
- package/dist/segments.d.ts +14 -0
- package/dist/time-panel.d.ts +30 -0
- package/dist/time.d.ts +24 -0
- package/dist/utils.d.ts +6 -0
- package/dist/wheel-math.d.ts +11 -0
- package/dist/wheel.d.ts +28 -0
- package/package.json +90 -0
- package/registry.json +76 -0
- package/src/calendar-panel.tsx +321 -0
- package/src/calendar.ts +118 -0
- package/src/date-time-picker.tsx +138 -0
- package/src/hooks.ts +28 -0
- package/src/index.ts +18 -0
- package/src/segmented-control.tsx +72 -0
- package/src/segments.ts +26 -0
- package/src/styles.css +91 -0
- package/src/time-panel.tsx +262 -0
- package/src/time.ts +71 -0
- package/src/utils.ts +19 -0
- package/src/wheel-math.ts +35 -0
- package/src/wheel.tsx +365 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Klaus Fan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# cupertino-datetime-picker
|
|
2
|
+
|
|
3
|
+
**[Documentation](https://cupertino-datetime-picker-docs.vercel.app)** ·
|
|
4
|
+
**[Installation](https://cupertino-datetime-picker-docs.vercel.app/docs/installation)** ·
|
|
5
|
+
**[npm](https://www.npmjs.com/package/cupertino-datetime-picker)**
|
|
6
|
+
|
|
7
|
+
The iOS 14+ compact date & time picker, for the web. A date pill and a time
|
|
8
|
+
pill; the date pill opens the inline calendar whose title turns into month and
|
|
9
|
+
year wheels, the time pill opens hour / minute / AM–PM wheels with a typed
|
|
10
|
+
field above them. Every part takes touch, mouse, trackpad and keyboard.
|
|
11
|
+
|
|
12
|
+
Built for [shadcn/ui](https://ui.shadcn.com) on
|
|
13
|
+
[Base UI](https://base-ui.com) popovers and Tailwind v4. No date library:
|
|
14
|
+
`Intl` supplies month names, weekday names, the 12/24-hour clock and the
|
|
15
|
+
first day of the week.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
As a shadcn registry item (the source lands in your project, under
|
|
20
|
+
`components/ui/cupertino/`):
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npx shadcn@latest add https://cupertino-datetime-picker-docs.vercel.app/r/cupertino-datetime-picker.json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or from npm:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
pnpm add cupertino-datetime-picker @base-ui/react
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```css
|
|
33
|
+
/* your Tailwind entry */
|
|
34
|
+
@import "tailwindcss";
|
|
35
|
+
@import "cupertino-datetime-picker/styles.css";
|
|
36
|
+
@source "../node_modules/cupertino-datetime-picker/dist";
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Use
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import { DateTimePicker } from "cupertino-datetime-picker";
|
|
43
|
+
|
|
44
|
+
<DateTimePicker value={date} onChange={setDate} />
|
|
45
|
+
<DateTimePicker mode="date" />
|
|
46
|
+
<DateTimePicker mode="time" minuteInterval={5} />
|
|
47
|
+
<DateTimePicker display="inline" locale="de-DE" />
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
| Prop | Default | |
|
|
51
|
+
| ------------------------------------- | -------------------- | ------------------------------------------------------ |
|
|
52
|
+
| `value` / `defaultValue` / `onChange` | | `Date \| null`. Controlled when `value` is given. |
|
|
53
|
+
| `mode` | `"dateTime"` | `"date"`, `"time"`, or both — `UIDatePicker.Mode`. |
|
|
54
|
+
| `display` | `"compact"` | `"compact"` pills with popovers, or `"inline"` panels. |
|
|
55
|
+
| `locale` | `navigator.language` | Drives names, clock, week start and the pill formats. |
|
|
56
|
+
| `hourCycle` | from locale | `"h12"` or `"h23"`. |
|
|
57
|
+
| `minuteInterval` | `1` | Minute wheel step, like `UIDatePicker.minuteInterval`. |
|
|
58
|
+
| `min` / `max` | | Days outside the range are disabled. |
|
|
59
|
+
|
|
60
|
+
The panels are exported on their own (`CalendarPanel`, `TimePanel`) as are
|
|
61
|
+
the primitives (`Wheel`, `WheelHighlight`, `SegmentedControl`).
|
|
62
|
+
|
|
63
|
+
Re-tint with `--cdp-tint` (and `--cdp-on-tint` for text on it); dark mode
|
|
64
|
+
follows a `.dark` (or `data-theme="dark"`) ancestor. Accessible names are
|
|
65
|
+
English by default; pass `labels` to `CalendarPanel` / `TimePanel` to
|
|
66
|
+
translate them — the visible text is already the locale's.
|
|
67
|
+
|
|
68
|
+
## What matches iOS
|
|
69
|
+
|
|
70
|
+
- Pills: 34pt, 8pt radius, tertiary fill, tint text while open.
|
|
71
|
+
- Calendar: "September 2026 ›" title, next/previous in tint, single-letter
|
|
72
|
+
weekdays, 20pt days in 40pt circles. Selected day is a tinted circle; today
|
|
73
|
+
is tint text; selected today is a filled tint circle. Only the rows the
|
|
74
|
+
month needs. Months slide in; the title cross-fades the grid into month and
|
|
75
|
+
year wheels. Horizontal swipe changes month.
|
|
76
|
+
- Wheels: native scroll with snap points, so touch and trackpad flings are
|
|
77
|
+
the platform's own. Mouse drag has its own deceleration. Rows tilt away
|
|
78
|
+
from the centre and fade at the edges; hour and minute wheels wrap.
|
|
79
|
+
- Time field: hour and minute segments. Digits auto-advance (`945` is 9:45,
|
|
80
|
+
`12` waits for the second digit, `13` becomes 3), arrows step, `a`/`p` set
|
|
81
|
+
the period, and the wheels spin to follow. Spin a wheel and the digits
|
|
82
|
+
follow back. Mobile keypads insert through `beforeinput`, so IMEs work.
|
|
83
|
+
- Segmented control for AM/PM with the sliding thumb.
|
|
84
|
+
- Popover springs in from its pill.
|
|
85
|
+
|
|
86
|
+
## Keyboard
|
|
87
|
+
|
|
88
|
+
| Where | Keys |
|
|
89
|
+
| ------------- | ------------------------------------------------------------------------------------------------- |
|
|
90
|
+
| Calendar grid | ← → ↑ ↓ move a day / week, Home/End week bounds, PageUp/PageDown month (Shift: year), Enter picks |
|
|
91
|
+
| Any wheel | ↑ ↓ one row, PageUp/PageDown five, Home/End, type a value to jump |
|
|
92
|
+
| Time field | digits, ↑ ↓ step, ← → between segments, `a` / `p`, Backspace clears |
|
|
93
|
+
| Popover | Escape closes |
|
|
94
|
+
|
|
95
|
+
All wheels are `spinbutton`s with `aria-valuenow` / `aria-valuetext`; the
|
|
96
|
+
grid is a `grid` of `gridcell`s with full-date names.
|
|
97
|
+
|
|
98
|
+
## Develop
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
pnpm install
|
|
102
|
+
pnpm dev # demo at http://localhost:5173
|
|
103
|
+
pnpm test # vitest: calendar math, clock, segment typing, fling math
|
|
104
|
+
pnpm e2e # Playwright: desktop Chrome + iPhone 15 (touch flings via CDP)
|
|
105
|
+
pnpm check # typecheck, lint, tests, build
|
|
106
|
+
pnpm registry:build # shadcn registry JSON into docs/public/r
|
|
107
|
+
pnpm docs # documentation site (Fumadocs) at http://localhost:3000
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Not yet
|
|
111
|
+
|
|
112
|
+
- RTL locales.
|
|
113
|
+
- `wheels` display for the date (day / month / year drums).
|
|
114
|
+
- Ranges.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type CalendarPanelLabels = {
|
|
3
|
+
previousMonth: string;
|
|
4
|
+
nextMonth: string;
|
|
5
|
+
month: string;
|
|
6
|
+
year: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const CALENDAR_LABELS: CalendarPanelLabels;
|
|
9
|
+
export type CalendarPanelProps = {
|
|
10
|
+
value: Date | null;
|
|
11
|
+
onChange: (date: Date) => void;
|
|
12
|
+
locale?: string;
|
|
13
|
+
min?: Date;
|
|
14
|
+
max?: Date;
|
|
15
|
+
/** Accessible names; visible text comes from `Intl`. */
|
|
16
|
+
labels?: Partial<CalendarPanelLabels>;
|
|
17
|
+
/** Injected for tests and stories. */
|
|
18
|
+
today?: Date;
|
|
19
|
+
className?: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* The iOS inline calendar: month title that opens month/year wheels, next
|
|
23
|
+
* and previous month, a grid of circles. Months slide, the wheels cross-fade
|
|
24
|
+
* in over the grid, a horizontal swipe changes month, and the keyboard walks
|
|
25
|
+
* the grid (arrows, Home/End, PageUp/PageDown, Enter).
|
|
26
|
+
*/
|
|
27
|
+
export declare function CalendarPanel({ value, onChange, locale, min, max, labels: labelsProp, today: todayProp, className, }: CalendarPanelProps): React.JSX.Element;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar arithmetic on local `Date`s, with no library. A picker only ever
|
|
3
|
+
* needs the month grid, day-level comparisons, and "same clock, other day".
|
|
4
|
+
*/
|
|
5
|
+
export type YearMonth = {
|
|
6
|
+
year: number;
|
|
7
|
+
month: number;
|
|
8
|
+
};
|
|
9
|
+
export declare function startOfDay(date: Date): Date;
|
|
10
|
+
export declare function isSameDay(a: Date | null | undefined, b: Date | null | undefined): boolean;
|
|
11
|
+
export declare function daysInMonth(year: number, month: number): number;
|
|
12
|
+
export declare function yearMonthOf(date: Date): YearMonth;
|
|
13
|
+
/** Months between `a` and `b`; negative when `b` is earlier. */
|
|
14
|
+
export declare function monthDiff(a: YearMonth, b: YearMonth): number;
|
|
15
|
+
export declare function shiftMonth(ym: YearMonth, by: number): YearMonth;
|
|
16
|
+
/** The same clock on another calendar day; the day is clamped into the month. */
|
|
17
|
+
export declare function withDay(base: Date, year: number, month: number, day: number): Date;
|
|
18
|
+
export declare function withTime(base: Date, hours: number, minutes: number): Date;
|
|
19
|
+
export declare function addDays(date: Date, days: number): Date;
|
|
20
|
+
export declare function addMonths(date: Date, months: number): Date;
|
|
21
|
+
/** Whether the whole day lies outside [min, max]. */
|
|
22
|
+
export declare function isDayDisabled(date: Date, min?: Date, max?: Date): boolean;
|
|
23
|
+
export type DayCell = {
|
|
24
|
+
date: Date;
|
|
25
|
+
inMonth: boolean;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Rows of seven for one month, starting on `weekStart` (0 = Sunday). Only as
|
|
29
|
+
* many rows as the month needs, like the iOS inline calendar.
|
|
30
|
+
*/
|
|
31
|
+
export declare function monthGrid(year: number, month: number, weekStart: number): DayCell[][];
|
|
32
|
+
/** First day of the week for a locale, 0 = Sunday … 6 = Saturday. */
|
|
33
|
+
export declare function weekStartFor(locale: string): number;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { HourCycle } from './time';
|
|
2
|
+
export type DateTimePickerProps = {
|
|
3
|
+
value?: Date | null;
|
|
4
|
+
defaultValue?: Date | null;
|
|
5
|
+
onChange?: (date: Date | null) => void;
|
|
6
|
+
/** Which parts are editable — `UIDatePicker.Mode`. */
|
|
7
|
+
mode?: "date" | "time" | "dateTime";
|
|
8
|
+
/** Pills that open popovers (`.compact`), or the panels laid out in place (`.inline`). */
|
|
9
|
+
display?: "compact" | "inline";
|
|
10
|
+
locale?: string;
|
|
11
|
+
hourCycle?: HourCycle;
|
|
12
|
+
minuteInterval?: number;
|
|
13
|
+
min?: Date;
|
|
14
|
+
max?: Date;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
className?: string;
|
|
17
|
+
/** Placeholder labels when there is no value. */
|
|
18
|
+
labels?: {
|
|
19
|
+
date?: string;
|
|
20
|
+
time?: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
/** The compact pill and its popover, for composing your own rows. */
|
|
24
|
+
export declare const pillClass = "inline-flex h-[34px] items-center rounded-lg bg-[var(--cdp-fill)] px-3 text-[17px] leading-none text-[var(--cdp-label)] transition-[background-color,color] outline-none hover:bg-[var(--cdp-fill-hover)] focus-visible:ring-2 focus-visible:ring-[var(--cdp-tint)] active:opacity-60 disabled:opacity-40 data-popup-open:text-[var(--cdp-tint)]";
|
|
25
|
+
export declare const popupClass = "cdp origin-(--transform-origin) rounded-[13px] bg-[var(--cdp-bg)] shadow-[var(--cdp-shadow)] outline-none data-open:animate-[cdp-pop-in_260ms_cubic-bezier(0.18,0.9,0.32,1.15)] data-closed:animate-[cdp-pop-out_140ms_ease-in]";
|
|
26
|
+
/**
|
|
27
|
+
* The iOS 14+ date picker for the web. Compact display shows the date and
|
|
28
|
+
* time as pills; each opens a popover — the calendar or the time panel —
|
|
29
|
+
* anchored to it. Inline display lays the panels out in place.
|
|
30
|
+
*/
|
|
31
|
+
export declare function DateTimePicker({ value: valueProp, defaultValue, onChange, mode, display, locale, hourCycle: hourCycleProp, minuteInterval, min, max, disabled, className, labels, }: DateTimePickerProps): import("react").JSX.Element;
|
package/dist/hooks.d.ts
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { DateTimePicker, pillClass, popupClass, type DateTimePickerProps, } from './date-time-picker';
|
|
2
|
+
export { CalendarPanel, CALENDAR_LABELS, type CalendarPanelLabels, type CalendarPanelProps, } from './calendar-panel';
|
|
3
|
+
export { TimePanel, TIME_LABELS, type TimePanelLabels, type TimePanelProps } from './time-panel';
|
|
4
|
+
export { Wheel, WheelHighlight, type WheelOption, type WheelProps } from './wheel';
|
|
5
|
+
export { SegmentedControl, type SegmentedOption } from './segmented-control';
|
|
6
|
+
export * from './calendar';
|
|
7
|
+
export * from './time';
|
|
8
|
+
export { typeDigit, stepValue, type DigitStep } from './segments';
|