@nexub/react 6.1.0 → 6.2.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/accessibility.json +31 -1
- package/dist/components/DateTimePicker/DateTimePicker.d.ts +20 -0
- package/dist/components/DateTimePicker/DateTimePicker.js +67 -0
- package/dist/components/DateTimePicker/index.d.ts +2 -0
- package/dist/components/DateTimePicker/index.js +4 -0
- package/dist/components/EventCalendar/EventCalendar.d.ts +38 -0
- package/dist/components/EventCalendar/EventCalendar.js +204 -0
- package/dist/components/EventCalendar/index.d.ts +2 -0
- package/dist/components/EventCalendar/index.js +4 -0
- package/dist/components/TimePicker/TimePicker.d.ts +15 -0
- package/dist/components/TimePicker/TimePicker.js +26 -0
- package/dist/components/TimePicker/index.d.ts +2 -0
- package/dist/components/TimePicker/index.js +4 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/styles.css +1 -1
- package/package.json +6 -6
package/accessibility.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "6.
|
|
2
|
+
"version": "6.2.0",
|
|
3
3
|
"standard": "WCAG 2.2 Level AA",
|
|
4
4
|
"method": {
|
|
5
5
|
"automated": "axe-core rules tagged wcag2a, wcag2aa, wcag21a, wcag21aa and wcag22aa, run on every Storybook story in light and dark, and on open popups (menus, listboxes, dialogs), on every pull request; a new violation fails the build.",
|
|
@@ -342,6 +342,15 @@
|
|
|
342
342
|
"keyboard": [],
|
|
343
343
|
"screenReader": []
|
|
344
344
|
},
|
|
345
|
+
{
|
|
346
|
+
"slug": "date-time-picker",
|
|
347
|
+
"name": "Date Time Picker",
|
|
348
|
+
"package": "@nexub/react",
|
|
349
|
+
"automated": "pass",
|
|
350
|
+
"exceptions": [],
|
|
351
|
+
"keyboard": [],
|
|
352
|
+
"screenReader": []
|
|
353
|
+
},
|
|
345
354
|
{
|
|
346
355
|
"slug": "dialog",
|
|
347
356
|
"name": "Dialog",
|
|
@@ -401,6 +410,15 @@
|
|
|
401
410
|
"keyboard": [],
|
|
402
411
|
"screenReader": []
|
|
403
412
|
},
|
|
413
|
+
{
|
|
414
|
+
"slug": "event-calendar",
|
|
415
|
+
"name": "Event Calendar",
|
|
416
|
+
"package": "@nexub/react",
|
|
417
|
+
"automated": "pass",
|
|
418
|
+
"exceptions": [],
|
|
419
|
+
"keyboard": [],
|
|
420
|
+
"screenReader": []
|
|
421
|
+
},
|
|
404
422
|
{
|
|
405
423
|
"slug": "eyebrow-chip",
|
|
406
424
|
"name": "Eyebrow Chip",
|
|
@@ -1127,6 +1145,18 @@
|
|
|
1127
1145
|
"Render it only while waiting and remove it when tokens start, so it is not announced again."
|
|
1128
1146
|
]
|
|
1129
1147
|
},
|
|
1148
|
+
{
|
|
1149
|
+
"slug": "time-picker",
|
|
1150
|
+
"name": "Time Picker",
|
|
1151
|
+
"package": "@nexub/react",
|
|
1152
|
+
"automated": "pass",
|
|
1153
|
+
"exceptions": [],
|
|
1154
|
+
"keyboard": [
|
|
1155
|
+
"ArrowUp / ArrowDown: Changes the focused segment (hour, minute, AM/PM).",
|
|
1156
|
+
"ArrowLeft / ArrowRight: Moves between segments."
|
|
1157
|
+
],
|
|
1158
|
+
"screenReader": []
|
|
1159
|
+
},
|
|
1130
1160
|
{
|
|
1131
1161
|
"slug": "toast",
|
|
1132
1162
|
"name": "Toast",
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { Locale } from 'date-fns';
|
|
3
|
+
export interface DateTimePickerProps {
|
|
4
|
+
/** Date and time in the reader's local time. */
|
|
5
|
+
value?: Date;
|
|
6
|
+
onChange?: (value: Date | undefined) => void;
|
|
7
|
+
/** Time used when a date is picked first. @default '09:00' */
|
|
8
|
+
defaultTime?: string;
|
|
9
|
+
minuteStep?: number;
|
|
10
|
+
minDate?: Date;
|
|
11
|
+
maxDate?: Date;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** IANA zone to name next to the fields (label only; the value stays local). */
|
|
14
|
+
timeZone?: string;
|
|
15
|
+
'aria-label'?: string;
|
|
16
|
+
className?: string;
|
|
17
|
+
locale?: Locale;
|
|
18
|
+
}
|
|
19
|
+
/** A DatePicker and a TimePicker that edit one `Date` together. */
|
|
20
|
+
export declare function DateTimePicker({ value, onChange, defaultTime, minuteStep, minDate, maxDate, disabled, timeZone, 'aria-label': ariaLabel, className, locale, }: DateTimePickerProps): React.JSX.Element;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "../../utils/cn.js";
|
|
5
|
+
import { DatePicker } from "../DatePicker/DatePicker.js";
|
|
6
|
+
import { TimePicker } from "../TimePicker/TimePicker.js";
|
|
7
|
+
import { useIntlLocale, useNexubMessages } from "../NexubProvider/NexubProvider.js";
|
|
8
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
9
|
+
const timeOf = (d) => `${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
|
10
|
+
const withTime = (d, time) => {
|
|
11
|
+
const [h = 0, m = 0] = time.split(":").map(Number);
|
|
12
|
+
const next = new Date(d);
|
|
13
|
+
next.setHours(h, m, 0, 0);
|
|
14
|
+
return next;
|
|
15
|
+
};
|
|
16
|
+
function DateTimePicker({
|
|
17
|
+
value,
|
|
18
|
+
onChange,
|
|
19
|
+
defaultTime = "09:00",
|
|
20
|
+
minuteStep,
|
|
21
|
+
minDate,
|
|
22
|
+
maxDate,
|
|
23
|
+
disabled,
|
|
24
|
+
timeZone,
|
|
25
|
+
"aria-label": ariaLabel,
|
|
26
|
+
className,
|
|
27
|
+
locale
|
|
28
|
+
}) {
|
|
29
|
+
const messages = useNexubMessages();
|
|
30
|
+
const intlLocale = useIntlLocale();
|
|
31
|
+
const [pendingTime, setPendingTime] = React.useState(defaultTime);
|
|
32
|
+
const time = value ? timeOf(value) : pendingTime;
|
|
33
|
+
const zoneName = timeZone ? new Intl.DateTimeFormat(intlLocale, { timeZone, timeZoneName: "shortOffset" }).formatToParts(value ?? /* @__PURE__ */ new Date()).find((p) => p.type === "timeZoneName")?.value ?? timeZone : void 0;
|
|
34
|
+
return /* @__PURE__ */ jsxs("div", { role: "group", "aria-label": ariaLabel, className: cn("flex flex-wrap items-center gap-2", className), children: [
|
|
35
|
+
/* @__PURE__ */ jsx("div", { className: "min-w-40 flex-1", children: /* @__PURE__ */ jsx(
|
|
36
|
+
DatePicker,
|
|
37
|
+
{
|
|
38
|
+
"aria-label": messages.dateLabel,
|
|
39
|
+
value,
|
|
40
|
+
onChange: (date) => onChange?.(date ? withTime(date, time) : void 0),
|
|
41
|
+
minDate,
|
|
42
|
+
maxDate,
|
|
43
|
+
disabled,
|
|
44
|
+
locale
|
|
45
|
+
}
|
|
46
|
+
) }),
|
|
47
|
+
/* @__PURE__ */ jsx(
|
|
48
|
+
TimePicker,
|
|
49
|
+
{
|
|
50
|
+
"aria-label": messages.timeLabel,
|
|
51
|
+
wrapperClassName: "w-36",
|
|
52
|
+
value: time,
|
|
53
|
+
minuteStep,
|
|
54
|
+
disabled,
|
|
55
|
+
onValueChange: (next) => {
|
|
56
|
+
if (!next) return;
|
|
57
|
+
if (value) onChange?.(withTime(value, next));
|
|
58
|
+
else setPendingTime(next);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
),
|
|
62
|
+
zoneName && /* @__PURE__ */ jsx("span", { className: "text-body-sm text-[var(--color-on-surface-muted)]", children: messages.timeZoneLabel(`${zoneName} (${timeZone})`) })
|
|
63
|
+
] });
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
DateTimePicker
|
|
67
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type Day } from 'date-fns';
|
|
3
|
+
export type EventCalendarView = 'month' | 'week';
|
|
4
|
+
export type EventTone = 'primary' | 'success' | 'warning' | 'error' | 'info';
|
|
5
|
+
export interface CalendarEvent {
|
|
6
|
+
id: string;
|
|
7
|
+
title: string;
|
|
8
|
+
start: Date;
|
|
9
|
+
/** Inclusive end; events spanning days show on each of them. */
|
|
10
|
+
end?: Date;
|
|
11
|
+
/** Hides the start time. */
|
|
12
|
+
allDay?: boolean;
|
|
13
|
+
/** @default 'primary' */
|
|
14
|
+
tone?: EventTone;
|
|
15
|
+
}
|
|
16
|
+
export interface EventCalendarProps {
|
|
17
|
+
events: CalendarEvent[];
|
|
18
|
+
/** Any day inside the shown month or week. */
|
|
19
|
+
date?: Date;
|
|
20
|
+
defaultDate?: Date;
|
|
21
|
+
onDateChange?: (date: Date) => void;
|
|
22
|
+
view?: EventCalendarView;
|
|
23
|
+
defaultView?: EventCalendarView;
|
|
24
|
+
onViewChange?: (view: EventCalendarView) => void;
|
|
25
|
+
onEventClick?: (event: CalendarEvent) => void;
|
|
26
|
+
/** A day's number, or its "N more" link in month view. */
|
|
27
|
+
onDayClick?: (date: Date) => void;
|
|
28
|
+
/** Events shown per day in month view before "N more". @default 3 */
|
|
29
|
+
maxEventsPerDay?: number;
|
|
30
|
+
/** 0 = Sunday. Defaults to the locale's first day of the week. */
|
|
31
|
+
weekStartsOn?: Day;
|
|
32
|
+
className?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A month or week grid of events. Display only: your app owns the events and
|
|
36
|
+
* decides what a click on an event or a day does.
|
|
37
|
+
*/
|
|
38
|
+
export declare function EventCalendar({ events, date: dateProp, defaultDate, onDateChange, view: viewProp, defaultView, onViewChange, onEventClick, onDayClick, maxEventsPerDay, weekStartsOn: weekStartsOnProp, className, }: EventCalendarProps): React.JSX.Element;
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import {
|
|
5
|
+
addDays,
|
|
6
|
+
addMonths,
|
|
7
|
+
addWeeks,
|
|
8
|
+
endOfDay,
|
|
9
|
+
endOfMonth,
|
|
10
|
+
endOfWeek,
|
|
11
|
+
format,
|
|
12
|
+
isSameDay,
|
|
13
|
+
isSameMonth,
|
|
14
|
+
startOfDay,
|
|
15
|
+
startOfMonth,
|
|
16
|
+
startOfWeek
|
|
17
|
+
} from "date-fns";
|
|
18
|
+
import { ChevronLeft, ChevronRight } from "@nexub/icons";
|
|
19
|
+
import { cn } from "../../utils/cn.js";
|
|
20
|
+
import { Button } from "../Button/Button.js";
|
|
21
|
+
import { IconButton } from "../IconButton/IconButton.js";
|
|
22
|
+
import { SegmentedControl } from "../SegmentedControl/SegmentedControl.js";
|
|
23
|
+
import { useControllableState } from "../../hooks/useControllableState.js";
|
|
24
|
+
import { useIntlLocale, useLocale, useNexubMessages } from "../NexubProvider/NexubProvider.js";
|
|
25
|
+
const tones = {
|
|
26
|
+
primary: "bg-[var(--color-primary-container)] text-[var(--color-on-primary-container)]",
|
|
27
|
+
success: "bg-[var(--color-success-container)] text-[var(--color-on-success-container)]",
|
|
28
|
+
warning: "bg-[var(--color-warning-container)] text-[var(--color-on-warning-container)]",
|
|
29
|
+
error: "bg-[var(--color-error-container)] text-[var(--color-on-error-container)]",
|
|
30
|
+
info: "bg-[var(--color-info-container)] text-[var(--color-on-info-container)]"
|
|
31
|
+
};
|
|
32
|
+
function localeWeekStart(locale) {
|
|
33
|
+
try {
|
|
34
|
+
const loc = new Intl.Locale(locale ?? new Intl.DateTimeFormat().resolvedOptions().locale);
|
|
35
|
+
const firstDay = loc.getWeekInfo?.().firstDay ?? loc.weekInfo?.firstDay;
|
|
36
|
+
return firstDay ? firstDay % 7 : 0;
|
|
37
|
+
} catch {
|
|
38
|
+
return 0;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function EventCalendar({
|
|
42
|
+
events,
|
|
43
|
+
date: dateProp,
|
|
44
|
+
defaultDate,
|
|
45
|
+
onDateChange,
|
|
46
|
+
view: viewProp,
|
|
47
|
+
defaultView = "month",
|
|
48
|
+
onViewChange,
|
|
49
|
+
onEventClick,
|
|
50
|
+
onDayClick,
|
|
51
|
+
maxEventsPerDay = 3,
|
|
52
|
+
weekStartsOn: weekStartsOnProp,
|
|
53
|
+
className
|
|
54
|
+
}) {
|
|
55
|
+
const t = useNexubMessages();
|
|
56
|
+
const { dir } = useLocale();
|
|
57
|
+
const intlLocale = useIntlLocale();
|
|
58
|
+
const [date = /* @__PURE__ */ new Date(), setDate] = useControllableState({
|
|
59
|
+
value: dateProp,
|
|
60
|
+
defaultValue: defaultDate ?? /* @__PURE__ */ new Date(),
|
|
61
|
+
onChange: onDateChange
|
|
62
|
+
});
|
|
63
|
+
const [view = "month", setView] = useControllableState({
|
|
64
|
+
value: viewProp,
|
|
65
|
+
defaultValue: defaultView,
|
|
66
|
+
onChange: onViewChange
|
|
67
|
+
});
|
|
68
|
+
const weekStartsOn = weekStartsOnProp ?? localeWeekStart(intlLocale);
|
|
69
|
+
const opts = { weekStartsOn };
|
|
70
|
+
const month = view === "month";
|
|
71
|
+
const first = startOfWeek(month ? startOfMonth(date) : date, opts);
|
|
72
|
+
const last = endOfWeek(month ? endOfMonth(date) : date, opts);
|
|
73
|
+
const days = [];
|
|
74
|
+
for (let d = first; d <= last; d = addDays(d, 1)) days.push(d);
|
|
75
|
+
const weeks = [];
|
|
76
|
+
for (let i = 0; i < days.length; i += 7) weeks.push(days.slice(i, i + 7));
|
|
77
|
+
const sorted = React.useMemo(
|
|
78
|
+
() => [...events].sort((a, b) => a.start.getTime() - b.start.getTime()),
|
|
79
|
+
[events]
|
|
80
|
+
);
|
|
81
|
+
const eventsOn = (day) => sorted.filter((e) => e.start <= endOfDay(day) && (e.end ?? e.start) >= startOfDay(day));
|
|
82
|
+
const fmt = (o) => new Intl.DateTimeFormat(intlLocale, o);
|
|
83
|
+
const title = month ? fmt({ month: "long", year: "numeric" }).format(date) : fmt({ month: "short", day: "numeric", year: "numeric" }).formatRange(days[0], days[6]);
|
|
84
|
+
const timeFmt = fmt({ timeStyle: "short" });
|
|
85
|
+
const fullFmt = fmt({ dateStyle: "full" });
|
|
86
|
+
const today = /* @__PURE__ */ new Date();
|
|
87
|
+
const step = (n) => setDate(month ? addMonths(date, n) : addWeeks(date, n));
|
|
88
|
+
const [Back, Forward] = dir === "rtl" ? [ChevronRight, ChevronLeft] : [ChevronLeft, ChevronRight];
|
|
89
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3", className), children: [
|
|
90
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
91
|
+
/* @__PURE__ */ jsx("h2", { "aria-live": "polite", className: "me-auto text-title-lg font-semibold text-[var(--color-on-surface)]", children: title }),
|
|
92
|
+
/* @__PURE__ */ jsx(Button, { variant: "outlined", size: "sm", onClick: () => setDate(/* @__PURE__ */ new Date()), children: t.today }),
|
|
93
|
+
/* @__PURE__ */ jsx(IconButton, { variant: "ghost", size: "sm", label: month ? t.previousMonth : t.previousWeek, onClick: () => step(-1), children: /* @__PURE__ */ jsx(Back, { size: "sm", "aria-hidden": "true" }) }),
|
|
94
|
+
/* @__PURE__ */ jsx(IconButton, { variant: "ghost", size: "sm", label: month ? t.nextMonth : t.nextWeek, onClick: () => step(1), children: /* @__PURE__ */ jsx(Forward, { size: "sm", "aria-hidden": "true" }) }),
|
|
95
|
+
/* @__PURE__ */ jsxs(
|
|
96
|
+
SegmentedControl.Root,
|
|
97
|
+
{
|
|
98
|
+
size: "sm",
|
|
99
|
+
"aria-label": t.calendarView,
|
|
100
|
+
value: view,
|
|
101
|
+
onValueChange: (v) => v && setView(v),
|
|
102
|
+
children: [
|
|
103
|
+
/* @__PURE__ */ jsx(SegmentedControl.Item, { value: "month", children: t.monthView }),
|
|
104
|
+
/* @__PURE__ */ jsx(SegmentedControl.Item, { value: "week", children: t.weekView })
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
] }),
|
|
109
|
+
/* @__PURE__ */ jsxs("table", { className: "w-full table-fixed border-collapse text-body-sm", children: [
|
|
110
|
+
/* @__PURE__ */ jsx("caption", { className: "sr-only", children: title }),
|
|
111
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: weeks[0].map((d) => /* @__PURE__ */ jsx(
|
|
112
|
+
"th",
|
|
113
|
+
{
|
|
114
|
+
scope: "col",
|
|
115
|
+
abbr: fmt({ weekday: "long" }).format(d),
|
|
116
|
+
className: "pb-2 text-label-md font-medium text-[var(--color-on-surface-muted)]",
|
|
117
|
+
children: fmt({ weekday: "short" }).format(d)
|
|
118
|
+
},
|
|
119
|
+
d.getDay()
|
|
120
|
+
)) }) }),
|
|
121
|
+
/* @__PURE__ */ jsx("tbody", { children: weeks.map((week) => /* @__PURE__ */ jsx("tr", { children: week.map((day) => {
|
|
122
|
+
const list = eventsOn(day);
|
|
123
|
+
const shown = month ? list.slice(0, maxEventsPerDay) : list;
|
|
124
|
+
const hidden = list.length - shown.length;
|
|
125
|
+
const isToday = isSameDay(day, today);
|
|
126
|
+
const outside = month && !isSameMonth(day, date);
|
|
127
|
+
return /* @__PURE__ */ jsxs(
|
|
128
|
+
"td",
|
|
129
|
+
{
|
|
130
|
+
"aria-current": isToday ? "date" : void 0,
|
|
131
|
+
className: cn(
|
|
132
|
+
"border border-[var(--color-outline-variant)] p-1 align-top",
|
|
133
|
+
month ? "h-28" : "h-80",
|
|
134
|
+
outside && "bg-[var(--color-surface-container-low)]"
|
|
135
|
+
),
|
|
136
|
+
children: [
|
|
137
|
+
/* @__PURE__ */ jsx(
|
|
138
|
+
DayNumber,
|
|
139
|
+
{
|
|
140
|
+
day,
|
|
141
|
+
label: fullFmt.format(day),
|
|
142
|
+
isToday,
|
|
143
|
+
muted: outside,
|
|
144
|
+
onClick: onDayClick
|
|
145
|
+
}
|
|
146
|
+
),
|
|
147
|
+
/* @__PURE__ */ jsx("ul", { className: "mt-1 flex flex-col gap-0.5", children: shown.map((e) => {
|
|
148
|
+
const time = e.allDay || !isSameDay(e.start, day) ? "" : timeFmt.format(e.start);
|
|
149
|
+
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
150
|
+
time && /* @__PURE__ */ jsx("span", { className: "me-1 tabular-nums opacity-80", children: time }),
|
|
151
|
+
e.title
|
|
152
|
+
] });
|
|
153
|
+
const cls = cn(
|
|
154
|
+
"block w-full truncate rounded-shape-min px-1.5 py-0.5 text-start text-label-md",
|
|
155
|
+
tones[e.tone ?? "primary"]
|
|
156
|
+
);
|
|
157
|
+
return /* @__PURE__ */ jsx("li", { children: onEventClick ? /* @__PURE__ */ jsx("button", { type: "button", className: cn(cls, "hover:opacity-90"), onClick: () => onEventClick(e), children: body }) : /* @__PURE__ */ jsx("span", { className: cls, children: body }) }, e.id);
|
|
158
|
+
}) }),
|
|
159
|
+
hidden > 0 && (onDayClick ? /* @__PURE__ */ jsx(
|
|
160
|
+
"button",
|
|
161
|
+
{
|
|
162
|
+
type: "button",
|
|
163
|
+
className: "min-h-6 px-1.5 text-label-md text-[var(--color-on-surface-variant)] hover:underline",
|
|
164
|
+
onClick: () => onDayClick(day),
|
|
165
|
+
children: t.moreCount(hidden)
|
|
166
|
+
}
|
|
167
|
+
) : /* @__PURE__ */ jsx("span", { className: "mt-0.5 block px-1.5 text-label-md text-[var(--color-on-surface-variant)]", children: t.moreCount(hidden) }))
|
|
168
|
+
]
|
|
169
|
+
},
|
|
170
|
+
day.toISOString()
|
|
171
|
+
);
|
|
172
|
+
}) }, week[0].toISOString())) })
|
|
173
|
+
] })
|
|
174
|
+
] });
|
|
175
|
+
}
|
|
176
|
+
function DayNumber({
|
|
177
|
+
day,
|
|
178
|
+
label,
|
|
179
|
+
isToday,
|
|
180
|
+
muted,
|
|
181
|
+
onClick
|
|
182
|
+
}) {
|
|
183
|
+
const cls = cn(
|
|
184
|
+
"inline-flex size-7 items-center justify-center rounded-full text-label-md tabular-nums",
|
|
185
|
+
isToday ? "bg-[var(--color-primary)] text-[var(--color-on-primary)]" : muted ? "text-[var(--color-on-surface-muted)]" : "text-[var(--color-on-surface)]"
|
|
186
|
+
);
|
|
187
|
+
const n = day.getDate();
|
|
188
|
+
return onClick ? /* @__PURE__ */ jsx(
|
|
189
|
+
"button",
|
|
190
|
+
{
|
|
191
|
+
type: "button",
|
|
192
|
+
"aria-label": label,
|
|
193
|
+
className: cn(cls, !isToday && "hover:bg-[var(--color-surface-container-high)]"),
|
|
194
|
+
onClick: () => onClick(day),
|
|
195
|
+
children: n
|
|
196
|
+
}
|
|
197
|
+
) : /* @__PURE__ */ jsxs("time", { dateTime: format(day, "yyyy-MM-dd"), className: cls, children: [
|
|
198
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: n }),
|
|
199
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: label })
|
|
200
|
+
] });
|
|
201
|
+
}
|
|
202
|
+
export {
|
|
203
|
+
EventCalendar
|
|
204
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type InputProps } from '../Input/Input.js';
|
|
3
|
+
export interface TimePickerProps extends Omit<InputProps, 'type' | 'value' | 'defaultValue' | 'onChange' | 'step'> {
|
|
4
|
+
/** 24-hour `"HH:mm"`; the field shows 12 or 24 hours from the reader's locale. */
|
|
5
|
+
value?: string;
|
|
6
|
+
defaultValue?: string;
|
|
7
|
+
onValueChange?: (value: string) => void;
|
|
8
|
+
/** Minutes between steps for the arrow keys and the picker. @default 1 */
|
|
9
|
+
minuteStep?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A time field built on the native `<input type="time">`: locale-aware 12/24h,
|
|
13
|
+
* keyboard segments, the platform's picker on phones, and form submission.
|
|
14
|
+
*/
|
|
15
|
+
export declare const TimePicker: React.ForwardRefExoticComponent<TimePickerProps & React.RefAttributes<HTMLInputElement>>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Input } from "../Input/Input.js";
|
|
5
|
+
import { useControllableState } from "../../hooks/useControllableState.js";
|
|
6
|
+
const TimePicker = React.forwardRef(function TimePicker2({ value: valueProp, defaultValue, onValueChange, minuteStep = 1, ...props }, ref) {
|
|
7
|
+
const [value = "", setValue] = useControllableState({
|
|
8
|
+
value: valueProp,
|
|
9
|
+
defaultValue: defaultValue ?? "",
|
|
10
|
+
onChange: onValueChange
|
|
11
|
+
});
|
|
12
|
+
return /* @__PURE__ */ jsx(
|
|
13
|
+
Input,
|
|
14
|
+
{
|
|
15
|
+
ref,
|
|
16
|
+
type: "time",
|
|
17
|
+
step: minuteStep * 60,
|
|
18
|
+
value,
|
|
19
|
+
onChange: (e) => setValue(e.target.value),
|
|
20
|
+
...props
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
export {
|
|
25
|
+
TimePicker
|
|
26
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -220,6 +220,12 @@ export { Fieldset } from './components/Fieldset/index.js';
|
|
|
220
220
|
export type { FieldsetProps } from './components/Fieldset/index.js';
|
|
221
221
|
export { InlineEdit } from './components/InlineEdit/index.js';
|
|
222
222
|
export type { InlineEditProps } from './components/InlineEdit/index.js';
|
|
223
|
+
export { TimePicker } from './components/TimePicker/index.js';
|
|
224
|
+
export type { TimePickerProps } from './components/TimePicker/index.js';
|
|
225
|
+
export { DateTimePicker } from './components/DateTimePicker/index.js';
|
|
226
|
+
export type { DateTimePickerProps } from './components/DateTimePicker/index.js';
|
|
227
|
+
export { EventCalendar } from './components/EventCalendar/index.js';
|
|
228
|
+
export type { EventCalendarProps, EventCalendarView, CalendarEvent, EventTone } from './components/EventCalendar/index.js';
|
|
223
229
|
export type { OTPInputProps } from './components/OTPInput/index.js';
|
|
224
230
|
export { DatePicker } from './components/DatePicker/index.js';
|
|
225
231
|
export type { DatePickerProps } from './components/DatePicker/index.js';
|
package/dist/index.js
CHANGED
|
@@ -124,6 +124,9 @@ import { OTPInput } from "./components/OTPInput/index.js";
|
|
|
124
124
|
import { Form, useForm } from "./components/Form/index.js";
|
|
125
125
|
import { Fieldset } from "./components/Fieldset/index.js";
|
|
126
126
|
import { InlineEdit } from "./components/InlineEdit/index.js";
|
|
127
|
+
import { TimePicker } from "./components/TimePicker/index.js";
|
|
128
|
+
import { DateTimePicker } from "./components/DateTimePicker/index.js";
|
|
129
|
+
import { EventCalendar } from "./components/EventCalendar/index.js";
|
|
127
130
|
import { DatePicker } from "./components/DatePicker/index.js";
|
|
128
131
|
import { DateRangePicker } from "./components/DateRangePicker/index.js";
|
|
129
132
|
import { todayIn } from "./components/DateRangePicker/index.js";
|
|
@@ -169,6 +172,7 @@ export {
|
|
|
169
172
|
DataTable,
|
|
170
173
|
DatePicker,
|
|
171
174
|
DateRangePicker,
|
|
175
|
+
DateTimePicker,
|
|
172
176
|
Dialog,
|
|
173
177
|
DiffView,
|
|
174
178
|
DonutChart,
|
|
@@ -177,6 +181,7 @@ export {
|
|
|
177
181
|
EmptyState,
|
|
178
182
|
EmptyStatePreset,
|
|
179
183
|
ErrorState,
|
|
184
|
+
EventCalendar,
|
|
180
185
|
EyebrowChip,
|
|
181
186
|
Fade,
|
|
182
187
|
Fieldset,
|
|
@@ -266,6 +271,7 @@ export {
|
|
|
266
271
|
ThemeProvider,
|
|
267
272
|
ThemeScript,
|
|
268
273
|
ThinkingIndicator,
|
|
274
|
+
TimePicker,
|
|
269
275
|
Toast,
|
|
270
276
|
Toaster,
|
|
271
277
|
Toggle,
|