@nexub/react 6.1.0 → 6.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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "6.1.0",
2
+ "version": "6.3.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",
@@ -1174,6 +1204,24 @@
1174
1204
  "keyboard": [],
1175
1205
  "screenReader": []
1176
1206
  },
1207
+ {
1208
+ "slug": "tree-view",
1209
+ "name": "Tree View",
1210
+ "package": "@nexub/react",
1211
+ "automated": "pass",
1212
+ "exceptions": [],
1213
+ "keyboard": [
1214
+ "ArrowDown / ArrowUp: Next or previous visible item.",
1215
+ "ArrowRight: Opens a closed item, or moves to its first child. Mirrored in RTL.",
1216
+ "ArrowLeft: Closes an open item, or moves to its parent. Mirrored in RTL.",
1217
+ "Home / End: First or last visible item.",
1218
+ "Enter / Space: Selects the item, or toggles its checkbox.",
1219
+ "Type a letter: Moves to the next item starting with the typed text."
1220
+ ],
1221
+ "screenReader": [
1222
+ "The tree is one tab stop (roving tabindex); it returns to the last focused or the selected item."
1223
+ ]
1224
+ },
1177
1225
  {
1178
1226
  "slug": "activity-feed",
1179
1227
  "name": "ActivityFeed",
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { type ColumnDef, type RowSelectionState, type RowData, type VisibilityState, type ColumnSizingState, type ColumnOrderState, type ColumnPinningState } from '@tanstack/react-table';
2
+ import { type ColumnDef, type RowSelectionState, type RowData, type VisibilityState, type ColumnSizingState, type ColumnOrderState, type ColumnPinningState, type ExpandedState } from '@tanstack/react-table';
3
3
  declare module '@tanstack/react-table' {
4
4
  interface ColumnMeta<TData extends RowData, TValue> {
5
5
  /** Horizontal alignment of the header and cells. Use 'end' for numbers. @default 'start' */
@@ -75,5 +75,14 @@ export interface DataTableProps<TData> extends React.HTMLAttributes<HTMLDivEleme
75
75
  pagination?: {
76
76
  pageSize?: number;
77
77
  };
78
+ /**
79
+ * Nested rows (a tree table): return a row's children. The first column gets
80
+ * an expand toggle and indents each level. Sorting sorts within each level.
81
+ */
82
+ getSubRows?: (row: TData, index: number) => TData[] | undefined;
83
+ /** Expanded rows by id, or `true` for all. */
84
+ expanded?: ExpandedState;
85
+ defaultExpanded?: ExpandedState;
86
+ onExpandedChange?: (expanded: ExpandedState) => void;
78
87
  }
79
- export declare function DataTable<TData>({ columns, data, enableSorting, enableRowSelection, selectionColumn, rowSelection: rowSelectionProp, onRowSelectionChange, getRowId, bulkActions, density: densityProp, defaultDensity, onDensityChange, columnVisibility: columnVisibilityProp, onColumnVisibilityChange, viewOptions, toolbar, enableColumnResizing, columnSizing: columnSizingProp, onColumnSizingChange, enableColumnReordering, columnOrder: columnOrderProp, onColumnOrderChange, columnPinning: columnPinningProp, onColumnPinningChange, maxHeight, grid, rowWindow, pagination, caption, captionHidden, className, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, ...props }: DataTableProps<TData>): React.JSX.Element;
88
+ export declare function DataTable<TData>({ columns, data, enableSorting, enableRowSelection, selectionColumn, rowSelection: rowSelectionProp, onRowSelectionChange, getRowId, bulkActions, density: densityProp, defaultDensity, onDensityChange, columnVisibility: columnVisibilityProp, onColumnVisibilityChange, viewOptions, toolbar, enableColumnResizing, columnSizing: columnSizingProp, onColumnSizingChange, enableColumnReordering, columnOrder: columnOrderProp, onColumnOrderChange, columnPinning: columnPinningProp, onColumnPinningChange, maxHeight, grid, rowWindow, pagination, getSubRows, expanded: expandedProp, defaultExpanded, onExpandedChange, caption, captionHidden, className, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, ...props }: DataTableProps<TData>): React.JSX.Element;
@@ -7,9 +7,10 @@ import {
7
7
  getSortedRowModel,
8
8
  getFilteredRowModel,
9
9
  getPaginationRowModel,
10
+ getExpandedRowModel,
10
11
  flexRender
11
12
  } from "@tanstack/react-table";
12
- import { ArrowUp, ArrowDown, ChevronsUpDown, SlidersHorizontal, X } from "@nexub/icons";
13
+ import { ArrowUp, ArrowDown, ChevronDown, ChevronRight, ChevronsUpDown, SlidersHorizontal, X } from "@nexub/icons";
13
14
  import { cn } from "../../utils/cn.js";
14
15
  import { disabledContainer, pressable } from "../../utils/control.js";
15
16
  import { floatingSurface } from "../../utils/surface.js";
@@ -102,6 +103,34 @@ const useAllRows = (count) => ({
102
103
  before: 0,
103
104
  after: 0
104
105
  });
106
+ function TreeCell({
107
+ row,
108
+ expandLabel,
109
+ collapseLabel,
110
+ children
111
+ }) {
112
+ const open = row.getIsExpanded();
113
+ const ref = React.useCallback(
114
+ (el) => {
115
+ if (el) el.style.paddingInlineStart = `${row.depth * 1.5}rem`;
116
+ },
117
+ [row.depth]
118
+ );
119
+ return /* @__PURE__ */ jsxs("div", { ref, className: "flex items-center gap-1", children: [
120
+ row.getCanExpand() ? /* @__PURE__ */ jsx(
121
+ "button",
122
+ {
123
+ type: "button",
124
+ "aria-expanded": open,
125
+ "aria-label": open ? collapseLabel : expandLabel,
126
+ onClick: row.toggleExpanded,
127
+ className: "-ms-1 inline-flex size-6 shrink-0 items-center justify-center rounded-shape-min text-[var(--color-on-surface-variant)] hover:bg-[var(--color-surface-container-high)]",
128
+ children: open ? /* @__PURE__ */ jsx(ChevronDown, { size: "xs", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(ChevronRight, { size: "xs", "aria-hidden": "true", className: "rtl:-scale-x-100" })
129
+ }
130
+ ) : /* @__PURE__ */ jsx("span", { className: "-ms-1 size-6 shrink-0", "aria-hidden": "true" }),
131
+ children
132
+ ] });
133
+ }
105
134
  const px = (n) => typeof n === "number" ? `${n}px` : n;
106
135
  const apply = (u, prev) => typeof u === "function" ? u(prev) : u;
107
136
  const columnLabel = (c) => typeof c.columnDef.header === "string" ? c.columnDef.header : c.id;
@@ -134,6 +163,10 @@ function DataTable({
134
163
  grid = false,
135
164
  rowWindow,
136
165
  pagination,
166
+ getSubRows,
167
+ expanded: expandedProp,
168
+ defaultExpanded,
169
+ onExpandedChange,
137
170
  caption,
138
171
  captionHidden = false,
139
172
  className,
@@ -174,6 +207,11 @@ function DataTable({
174
207
  defaultValue: {},
175
208
  onChange: onColumnPinningChange
176
209
  });
210
+ const [expanded = {}, setExpanded] = useControllableState({
211
+ value: expandedProp,
212
+ defaultValue: defaultExpanded ?? {},
213
+ onChange: onExpandedChange
214
+ });
177
215
  const [announcement, setAnnouncement] = React.useState("");
178
216
  const tableRef = React.useRef(null);
179
217
  const gridNav = React.useMemo(() => createGridNavigation(dir), [dir]);
@@ -223,9 +261,12 @@ function DataTable({
223
261
  columnVisibility,
224
262
  columnSizing,
225
263
  columnOrder,
226
- columnPinning
264
+ columnPinning,
265
+ expanded: getSubRows ? expanded : void 0
227
266
  }),
228
267
  [
268
+ getSubRows,
269
+ expanded,
229
270
  enableSorting,
230
271
  sorting,
231
272
  enableRowSelection,
@@ -257,6 +298,12 @@ function DataTable({
257
298
  getSortedRowModel: enableSorting ? getSortedRowModel() : void 0,
258
299
  getFilteredRowModel: getFilteredRowModel(),
259
300
  getPaginationRowModel: pagination ? getPaginationRowModel() : void 0,
301
+ getSubRows,
302
+ getExpandedRowModel: getSubRows ? getExpandedRowModel() : void 0,
303
+ onExpandedChange: getSubRows ? (u) => setExpanded(apply(u, expanded)) : void 0,
304
+ // With pages, count top-level rows so a parent and its children stay together
305
+ // (TanStack then expands inside the page model; without pages it must not).
306
+ paginateExpandedRows: !pagination,
260
307
  enableRowSelection,
261
308
  manualPagination: false
262
309
  });
@@ -466,7 +513,7 @@ function DataTable({
466
513
  "data-index": i,
467
514
  "aria-rowindex": rowWin.virtual ? i + 2 : void 0,
468
515
  "data-state": enableRowSelection && row.getIsSelected() ? "selected" : void 0,
469
- children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx(
516
+ children: row.getVisibleCells().map((cell, _i, cells) => /* @__PURE__ */ jsx(
470
517
  TableCell,
471
518
  {
472
519
  ref: pinned || enableColumnResizing ? placeCell(cell.column) : void 0,
@@ -476,7 +523,7 @@ function DataTable({
476
523
  pinClass(cell.column),
477
524
  enableColumnResizing && "truncate"
478
525
  ),
479
- children: flexRender(cell.column.columnDef.cell, cell.getContext())
526
+ children: getSubRows && cell === cells.find((c) => c.column.id !== "__select") ? /* @__PURE__ */ jsx(TreeCell, { row, expandLabel: messages.expandRow, collapseLabel: messages.collapseRow, children: flexRender(cell.column.columnDef.cell, cell.getContext()) }) : flexRender(cell.column.columnDef.cell, cell.getContext())
480
527
  },
481
528
  cell.id
482
529
  ))
@@ -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,2 @@
1
+ export { DateTimePicker } from './DateTimePicker.js';
2
+ export type { DateTimePickerProps } from './DateTimePicker.js';
@@ -0,0 +1,4 @@
1
+ import { DateTimePicker } from "./DateTimePicker.js";
2
+ export {
3
+ DateTimePicker
4
+ };
@@ -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,2 @@
1
+ export { EventCalendar } from './EventCalendar.js';
2
+ export type { EventCalendarProps, EventCalendarView, CalendarEvent, EventTone } from './EventCalendar.js';
@@ -0,0 +1,4 @@
1
+ import { EventCalendar } from "./EventCalendar.js";
2
+ export {
3
+ EventCalendar
4
+ };
@@ -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
+ };
@@ -0,0 +1,2 @@
1
+ export { TimePicker } from './TimePicker.js';
2
+ export type { TimePickerProps } from './TimePicker.js';
@@ -0,0 +1,4 @@
1
+ import { TimePicker } from "./TimePicker.js";
2
+ export {
3
+ TimePicker
4
+ };
@@ -0,0 +1,38 @@
1
+ import * as React from 'react';
2
+ export interface TreeNode {
3
+ id: string;
4
+ label: React.ReactNode;
5
+ /** Text for type-ahead when `label` isn't a string. */
6
+ textValue?: string;
7
+ icon?: React.ReactNode;
8
+ children?: TreeNode[];
9
+ /** Children exist but aren't loaded yet: expanding calls `onLoadChildren`. */
10
+ hasChildren?: boolean;
11
+ disabled?: boolean;
12
+ }
13
+ export interface TreeViewProps {
14
+ nodes: TreeNode[];
15
+ 'aria-label'?: string;
16
+ 'aria-labelledby'?: string;
17
+ expanded?: string[];
18
+ defaultExpanded?: string[];
19
+ onExpandedChange?: (ids: string[]) => void;
20
+ /** Single selection (ignored when `checkable`). */
21
+ selected?: string | null;
22
+ defaultSelected?: string | null;
23
+ onSelectedChange?: (id: string | null) => void;
24
+ /** Checkboxes with tri-state parents; `checked` lists every checked id, parents included. */
25
+ checkable?: boolean;
26
+ checked?: string[];
27
+ defaultChecked?: string[];
28
+ onCheckedChange?: (ids: string[]) => void;
29
+ /** Load a `hasChildren` node's children, then pass them in through `nodes`. */
30
+ onLoadChildren?: (node: TreeNode) => Promise<unknown>;
31
+ className?: string;
32
+ }
33
+ /**
34
+ * A hierarchy people can browse with the keyboard (ARIA tree): Arrow keys move
35
+ * and expand, Home/End jump, typing finds an item. Optional lazy children and
36
+ * tri-state checkboxes.
37
+ */
38
+ export declare function TreeView({ nodes, expanded: expandedProp, defaultExpanded, onExpandedChange, selected: selectedProp, defaultSelected, onSelectedChange, checkable, checked: checkedProp, defaultChecked, onCheckedChange, onLoadChildren, className, ...aria }: TreeViewProps): React.JSX.Element;