atlas-react-kit 0.13.0 → 1.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/COMPONENTS.md +144 -120
- package/DESIGN_RULES.md +53 -32
- package/README.md +12 -53
- package/dist/accordion.d.ts +1 -0
- package/dist/avatar.d.ts +1 -0
- package/dist/badge.d.ts +2 -3
- package/dist/breadcrumb.d.ts +2 -3
- package/dist/button.d.ts +2 -3
- package/dist/calendar.d.ts +2 -0
- package/dist/card.d.ts +3 -0
- package/dist/chart.d.ts +152 -0
- package/dist/chart.js +177 -0
- package/dist/color-legend.d.ts +8 -0
- package/dist/combobox.d.ts +13 -4
- package/dist/combobox.js +1 -8
- package/dist/date-picker.d.ts +26 -3
- package/dist/date-picker.js +37 -31
- package/dist/date-time-picker.d.ts +5 -2
- package/dist/date-time-picker.js +25 -38
- package/dist/dialog.d.ts +1 -0
- package/dist/dialog.js +4 -2
- package/dist/dropdown-menu.d.ts +9 -8
- package/dist/empty-panel.d.ts +8 -2
- package/dist/empty-panel.js +2 -2
- package/dist/error-boundary.d.ts +6 -1
- package/dist/field.d.ts +3 -0
- package/dist/field.js +1 -1
- package/dist/form/checkbox-field.d.ts +45 -0
- package/dist/form/checkbox-field.js +39 -0
- package/dist/form/combobox-field.d.ts +13 -0
- package/dist/form/combobox-field.js +14 -0
- package/dist/form/control-field.d.ts +6 -7
- package/dist/form/date-picker-field.d.ts +12 -21
- package/dist/form/date-picker-field.js +5 -4
- package/dist/form/date-time-picker-field.d.ts +7 -22
- package/dist/form/date-time-picker-field.js +4 -3
- package/dist/form/feedback-field.d.ts +2 -0
- package/dist/form/field-error.d.ts +35 -3
- package/dist/form/field-shell.d.ts +35 -6
- package/dist/form/field-shell.js +1 -1
- package/dist/form/focus-first-invalid.d.ts +28 -0
- package/dist/form/focus-first-invalid.js +29 -0
- package/dist/form/markdown-field.d.ts +4 -16
- package/dist/form/select-field.d.ts +13 -7
- package/dist/form/select-field.js +3 -2
- package/dist/form/text-field.d.ts +29 -10
- package/dist/form/text-field.js +4 -0
- package/dist/form/toggle-group-field.d.ts +30 -0
- package/dist/form/toggle-group-field.js +19 -0
- package/dist/info-tip.d.ts +10 -1
- package/dist/internal/as-child.d.ts +8 -0
- package/dist/internal/as-child.js +1 -0
- package/dist/internal/form-control.d.ts +3 -2
- package/dist/internal/form-control.js +3 -2
- package/dist/internal/kanban-layout.d.ts +55 -0
- package/dist/internal/kanban-layout.js +80 -0
- package/dist/internal/kanban-plugins.d.ts +17 -0
- package/dist/internal/kanban-plugins.js +17 -0
- package/dist/internal/listbox-navigation.d.ts +0 -11
- package/dist/internal/listbox-navigation.js +2 -2
- package/dist/internal/listbox-option.d.ts +0 -15
- package/dist/internal/listbox-option.js +1 -1
- package/dist/internal/use-drag-scroll.d.ts +17 -0
- package/dist/internal/use-drag-scroll.js +98 -0
- package/dist/internal/use-media-query.d.ts +4 -2
- package/dist/internal/use-media-query.js +11 -15
- package/dist/kanban.d.ts +84 -0
- package/dist/kanban.js +197 -0
- package/dist/markdown.d.ts +2 -0
- package/dist/meter.d.ts +7 -0
- package/dist/nav-link.d.ts +15 -6
- package/dist/nav-link.js +14 -4
- package/dist/next/nav-link.d.ts +6 -3
- package/dist/next/nav-link.js +8 -6
- package/dist/next/period-stepper.d.ts +11 -0
- package/dist/next/period-stepper.js +16 -0
- package/dist/next/tabs-nav-link.d.ts +6 -0
- package/dist/next/tabs-nav-link.js +8 -3
- package/dist/page-header.d.ts +19 -0
- package/dist/page-header.js +11 -0
- package/dist/pagination.d.ts +2 -0
- package/dist/period-stepper.d.ts +32 -0
- package/dist/period-stepper.js +27 -0
- package/dist/picker-shell.d.ts +33 -18
- package/dist/picker-shell.js +12 -10
- package/dist/progress.d.ts +1 -0
- package/dist/search-picker.d.ts +12 -0
- package/dist/select.d.ts +1 -0
- package/dist/skip-link.d.ts +7 -0
- package/dist/skip-link.js +10 -0
- package/dist/slider.d.ts +11 -0
- package/dist/sortable-table-head.d.ts +2 -0
- package/dist/stat-tile.d.ts +5 -0
- package/dist/table-body-skeleton.d.ts +2 -0
- package/dist/table.d.ts +1 -0
- package/dist/tabs.d.ts +27 -12
- package/dist/tabs.js +23 -10
- package/dist/toast.d.ts +7 -1
- package/dist/toggle-group.d.ts +9 -2
- package/dist/toggle-group.js +2 -1
- package/package.json +72 -6
- package/skills/atlas-react-kit/SKILL.md +46 -40
- package/theme.css +13 -0
package/dist/kanban.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { DragDropProvider, DragOverlay, useDragOperation, useDroppable, } from "@dnd-kit/react";
|
|
5
|
+
import { isSortable, useSortable } from "@dnd-kit/react/sortable";
|
|
6
|
+
import { CheckCircle2, ChevronLeft, ChevronRight, GripVertical, Trash2, } from "lucide-react";
|
|
7
|
+
import { Button } from "./button.js";
|
|
8
|
+
import { KANBAN_COMPLETE_ID, KANBAN_DELETE_ID, buildKanbanGroups, kanbanOverflowEdges, kanbanScrollBy, resolveKanbanDrop, } from "./internal/kanban-layout.js";
|
|
9
|
+
import { configureCardSortablePlugins, configureKanbanPlugins, } from "./internal/kanban-plugins.js";
|
|
10
|
+
import { Skeleton } from "./skeleton.js";
|
|
11
|
+
import { cn } from "./utils.js";
|
|
12
|
+
/** Column droppables lose to cards, so a drop lands between cards. */
|
|
13
|
+
const COLUMN_DROP_PRIORITY = 1;
|
|
14
|
+
/** Rail zones beat columns when both are under the pointer. */
|
|
15
|
+
const ACTION_ZONE_PRIORITY = 10;
|
|
16
|
+
const columnSize = "w-72 min-w-72 min-h-[min(70vh,32rem)]";
|
|
17
|
+
/**
|
|
18
|
+
* Drag-and-drop board built on dnd-kit. The consumer owns `items` and maps
|
|
19
|
+
* each to a column; the board derives its layout from them, so an optimistic
|
|
20
|
+
* cache update is the only state. Cards drag by their grip, the body stays
|
|
21
|
+
* clickable, and off-screen columns get edge fades and scroll buttons.
|
|
22
|
+
*/
|
|
23
|
+
function KanbanBoard({ columns, items, getColumnId, onMove, onComplete, onDelete, renderCard, onCardClick, isLoading = false, emptyLabel = "Drop here", completeLabel = "Finish", deleteLabel = "Remove", className, scrollerClassName, columnClassName, cardClassName, ...props }) {
|
|
24
|
+
const scrollerRef = React.useRef(null);
|
|
25
|
+
const overflow = useOverflowEdges(scrollerRef, columns.length, items.length);
|
|
26
|
+
const itemById = React.useMemo(() => new Map(items.map((item) => [item.id, item])), [items]);
|
|
27
|
+
const groups = React.useMemo(() => buildKanbanGroups(columns, items, getColumnId), [columns, items, getColumnId]);
|
|
28
|
+
const showSkeletons = isLoading && items.length === 0;
|
|
29
|
+
const dimmed = isLoading && !showSkeletons;
|
|
30
|
+
const handleDragOver = React.useCallback((event) => {
|
|
31
|
+
// Layout comes from `items`; stop dnd-kit moving cards between groups.
|
|
32
|
+
event.preventDefault();
|
|
33
|
+
}, []);
|
|
34
|
+
const handleDragEnd = React.useCallback((event) => {
|
|
35
|
+
if (event.canceled)
|
|
36
|
+
return;
|
|
37
|
+
const { source, target } = event.operation;
|
|
38
|
+
if (!source || !isSortable(source))
|
|
39
|
+
return;
|
|
40
|
+
const drop = resolveKanbanDrop({
|
|
41
|
+
itemId: String(source.id),
|
|
42
|
+
targetId: target ? String(target.id) : null,
|
|
43
|
+
targetGroup: target && isSortable(target) && target.group != null
|
|
44
|
+
? String(target.group)
|
|
45
|
+
: null,
|
|
46
|
+
initialGroup: source.initialGroup != null ? String(source.initialGroup) : null,
|
|
47
|
+
currentGroup: source.group != null ? String(source.group) : null,
|
|
48
|
+
index: typeof source.index === "number" ? source.index : undefined,
|
|
49
|
+
}, groups);
|
|
50
|
+
if (!drop)
|
|
51
|
+
return;
|
|
52
|
+
if (drop.kind === "complete")
|
|
53
|
+
return onComplete?.(drop.itemId);
|
|
54
|
+
if (drop.kind === "delete")
|
|
55
|
+
return onDelete?.(drop.itemId);
|
|
56
|
+
const item = itemById.get(drop.itemId);
|
|
57
|
+
if (!item)
|
|
58
|
+
return;
|
|
59
|
+
onMove(item, drop.toColumnId, {
|
|
60
|
+
beforePosition: drop.beforeId
|
|
61
|
+
? itemById.get(drop.beforeId)?.position
|
|
62
|
+
: undefined,
|
|
63
|
+
afterPosition: drop.afterId
|
|
64
|
+
? itemById.get(drop.afterId)?.position
|
|
65
|
+
: undefined,
|
|
66
|
+
});
|
|
67
|
+
}, [groups, itemById, onComplete, onDelete, onMove]);
|
|
68
|
+
const scrollToStart = React.useCallback(() => kanbanScrollBy(scrollerRef.current, -1), []);
|
|
69
|
+
const scrollToEnd = React.useCallback(() => kanbanScrollBy(scrollerRef.current, 1), []);
|
|
70
|
+
const renderOverlay = React.useCallback((source) => {
|
|
71
|
+
const item = source ? itemById.get(String(source.id)) : undefined;
|
|
72
|
+
if (!item)
|
|
73
|
+
return null;
|
|
74
|
+
return (_jsxs("div", { "data-slot": "kanban-drag-overlay", className: cn(cardChrome, "shadow-lg ring-2 ring-ring/30", cardClassName), children: [_jsx("div", { className: cn(handleChrome, "cursor-grabbing"), children: _jsx(GripVertical, { className: "size-4", "aria-hidden": true }) }), _jsx("div", { className: "min-w-0 flex-1 p-3", children: renderCard(item) })] }));
|
|
75
|
+
}, [cardClassName, itemById, renderCard]);
|
|
76
|
+
// `min-w-0` lets a flex or grid parent shrink the board so the scroller,
|
|
77
|
+
// not the page, overflows.
|
|
78
|
+
return (_jsx("div", { "data-slot": "kanban-board", className: cn("min-w-0", className), ...props, children: _jsxs(DragDropProvider, { plugins: configureKanbanPlugins, onDragOver: handleDragOver, onDragEnd: handleDragEnd, children: [_jsxs("div", { className: "relative min-w-0", children: [_jsx("div", { ref: scrollerRef, "data-slot": "kanban-scroller", "data-loading": dimmed || undefined, "data-overflow-start": overflow.start || undefined, "data-overflow-end": overflow.end || undefined, onScroll: overflow.measure, className: cn("flex min-w-0 gap-4 overflow-x-auto pb-2",
|
|
79
|
+
// AutoScroller scrolls in small steps near the edge; mandatory
|
|
80
|
+
// snap would pull each one back, so it is off mid-drag.
|
|
81
|
+
"snap-x snap-mandatory scroll-px-2 has-data-dragging:snap-none", "data-loading:opacity-60", scrollerClassName), children: columns.map((column) => {
|
|
82
|
+
const ids = groups[column.id] ?? [];
|
|
83
|
+
return (_jsx(KanbanColumnView, { column: column, count: showSkeletons ? 0 : ids.length, emptyLabel: column.emptyLabel ?? emptyLabel, loading: showSkeletons, className: columnClassName, children: ids.map((id, index) => {
|
|
84
|
+
const item = itemById.get(id);
|
|
85
|
+
if (!item)
|
|
86
|
+
return null;
|
|
87
|
+
return (_jsx(KanbanCardView, { item: item, index: index, column: column.id, onCardClick: onCardClick, className: cardClassName, renderCard: renderCard }, id));
|
|
88
|
+
}) }, column.id));
|
|
89
|
+
}) }), _jsx(OverflowFade, { side: "start", visible: overflow.start }), _jsx(OverflowFade, { side: "end", visible: overflow.end }), overflow.start ? (_jsx(ScrollButton, { side: "start", onClick: scrollToStart })) : null, overflow.end ? (_jsx(ScrollButton, { side: "end", onClick: scrollToEnd })) : null, overflow.start || overflow.end ? (_jsx("p", { className: "sr-only", children: "More columns available. Scroll horizontally to see them." })) : null] }), onComplete || onDelete ? (_jsx(ActionRail, { completeLabel: onComplete ? completeLabel : null, deleteLabel: onDelete ? deleteLabel : null })) : null, _jsx(DragOverlay, { dropAnimation: null, children: renderOverlay })] }) }));
|
|
90
|
+
}
|
|
91
|
+
function useOverflowEdges(ref, columnCount, itemCount) {
|
|
92
|
+
const [edges, setEdges] = React.useState({
|
|
93
|
+
start: false,
|
|
94
|
+
end: false,
|
|
95
|
+
});
|
|
96
|
+
const measure = React.useCallback(() => {
|
|
97
|
+
const element = ref.current;
|
|
98
|
+
if (!element)
|
|
99
|
+
return;
|
|
100
|
+
const next = kanbanOverflowEdges(element.scrollLeft, element.clientWidth, element.scrollWidth);
|
|
101
|
+
// Scroll fires every frame; keep the old object so the board (and every
|
|
102
|
+
// card in it) re-renders only when an edge appears or goes.
|
|
103
|
+
setEdges((edges) => edges.start === next.start && edges.end === next.end ? edges : next);
|
|
104
|
+
}, [ref]);
|
|
105
|
+
React.useLayoutEffect(() => {
|
|
106
|
+
const element = ref.current;
|
|
107
|
+
if (!element || typeof ResizeObserver === "undefined")
|
|
108
|
+
return;
|
|
109
|
+
measure();
|
|
110
|
+
const observer = new ResizeObserver(measure);
|
|
111
|
+
observer.observe(element);
|
|
112
|
+
for (const child of element.children)
|
|
113
|
+
observer.observe(child);
|
|
114
|
+
return () => observer.disconnect();
|
|
115
|
+
}, [columnCount, itemCount, measure, ref]);
|
|
116
|
+
return { ...edges, measure };
|
|
117
|
+
}
|
|
118
|
+
function KanbanColumnView({ column, count, emptyLabel, loading, className, children, }) {
|
|
119
|
+
const { ref, isDropTarget } = useDroppable({
|
|
120
|
+
id: column.id,
|
|
121
|
+
type: "column",
|
|
122
|
+
accept: "item",
|
|
123
|
+
collisionPriority: COLUMN_DROP_PRIORITY,
|
|
124
|
+
});
|
|
125
|
+
const empty = count === 0;
|
|
126
|
+
return (_jsxs("div", { ref: ref, "data-slot": "kanban-column", "data-drop-target": isDropTarget || undefined, className: cn("flex shrink-0 snap-start flex-col gap-3 p-3", "bg-muted/40 ring-1 ring-foreground/5", "data-drop-target:bg-muted/60 data-drop-target:ring-2 data-drop-target:ring-ring/60", columnSize, className), children: [_jsxs("header", { "data-slot": "kanban-column-header", className: "flex items-start justify-between gap-2", children: [_jsxs("span", { className: "flex items-center gap-2 text-xs font-semibold tracking-widest uppercase", children: [column.color ? (_jsx("span", { "aria-hidden": true, className: "size-2 shrink-0 rounded-full", style: { backgroundColor: column.color } })) : null, _jsx("span", { className: "leading-tight", children: column.label })] }), _jsxs("span", { className: "flex shrink-0 flex-col items-end gap-0.5 text-muted-foreground tabular-nums", children: [_jsx("span", { className: "text-xs", children: count }), column.badge ? (_jsx("span", { className: "text-[10px] font-medium", children: column.badge })) : null] })] }), _jsx("div", { className: "flex min-h-32 flex-1 flex-col gap-2 overflow-y-auto pr-1", children: loading ? (_jsxs(_Fragment, { children: [_jsx(Skeleton, { className: "h-20" }), _jsx(Skeleton, { className: "h-16" })] })) : (_jsxs(_Fragment, { children: [children, _jsx("p", { "data-slot": "kanban-column-empty", "aria-hidden": !empty, className: cn("border border-dashed px-3 py-6 text-center text-xs text-muted-foreground", !empty && "hidden"), children: emptyLabel })] })) })] }));
|
|
127
|
+
}
|
|
128
|
+
const cardChrome = cn("flex border border-border bg-card text-card-foreground");
|
|
129
|
+
const handleChrome = cn("flex shrink-0 items-center self-stretch border-r border-border", "bg-muted/30 px-1.5 text-muted-foreground");
|
|
130
|
+
function stopClick(event) {
|
|
131
|
+
event.stopPropagation();
|
|
132
|
+
}
|
|
133
|
+
function KanbanCardViewImpl({ item, index, column, onCardClick, className, renderCard, }) {
|
|
134
|
+
const children = renderCard(item);
|
|
135
|
+
const { handleRef, ref, isDragging } = useSortable({
|
|
136
|
+
id: item.id,
|
|
137
|
+
index,
|
|
138
|
+
type: "item",
|
|
139
|
+
accept: "item",
|
|
140
|
+
group: column,
|
|
141
|
+
transition: null,
|
|
142
|
+
plugins: configureCardSortablePlugins,
|
|
143
|
+
});
|
|
144
|
+
return (_jsxs("div", { ref: ref, "data-slot": "kanban-card", "data-dragging": isDragging || undefined, className: cn(cardChrome, "shadow-sm transition-[box-shadow,opacity,border-color]",
|
|
145
|
+
// The overlay moves; the source keeps its slot.
|
|
146
|
+
"data-dragging:pointer-events-none data-dragging:invisible",
|
|
147
|
+
// One ring on the card for the grip and the body alike.
|
|
148
|
+
"has-focus-visible:ring-2 has-focus-visible:ring-ring has-focus-visible:ring-offset-2 has-focus-visible:ring-offset-background", onCardClick && "hover:border-foreground/15", className), children: [_jsx("button", { type: "button", ref: handleRef, "data-slot": "kanban-card-handle", "aria-label": "Drag to move", onClick: stopClick, className: cn(handleChrome, "cursor-grab outline-none hover:bg-muted/50 active:cursor-grabbing"), children: _jsx(GripVertical, { className: "size-4", "aria-hidden": true }) }), onCardClick ? (_jsx("button", { type: "button", "data-slot": "kanban-card-body", onClick: () => onCardClick(item), className: "min-w-0 flex-1 cursor-pointer p-3 text-left outline-none hover:bg-muted/20", children: children })) : (_jsx("div", { "data-slot": "kanban-card-body", className: "min-w-0 flex-1 p-3", children: children }))] }));
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Memoized so a board update re-renders only the cards whose item, index or
|
|
152
|
+
* column changed, when `renderCard` and the other props keep their identity.
|
|
153
|
+
*/
|
|
154
|
+
const KanbanCardView = React.memo(KanbanCardViewImpl);
|
|
155
|
+
/**
|
|
156
|
+
* Finish / Remove zones under the board while a card drags. Not sticky: a
|
|
157
|
+
* sticky rail overlapping tall columns stole their drops.
|
|
158
|
+
*/
|
|
159
|
+
function ActionRail({ completeLabel, deleteLabel, }) {
|
|
160
|
+
const dragging = useDragOperation().source != null;
|
|
161
|
+
return (_jsxs("div", { "data-slot": "kanban-action-rail", "aria-hidden": !dragging, className: cn("relative z-20 -mx-1 mt-3 flex flex-col gap-2 bg-background px-1 pb-1 sm:flex-row", !dragging && "pointer-events-none"), children: [completeLabel != null ? (_jsx(ActionZone, { id: KANBAN_COMPLETE_ID, label: completeLabel, regionLabel: "Drop here to finish", icon: CheckCircle2, tone: "success", visible: dragging })) : null, deleteLabel != null ? (_jsx(ActionZone, { id: KANBAN_DELETE_ID, label: deleteLabel, regionLabel: "Drop here to remove", icon: Trash2, tone: "destructive", visible: dragging })) : null] }));
|
|
162
|
+
}
|
|
163
|
+
const zoneTone = {
|
|
164
|
+
success: {
|
|
165
|
+
idle: "border-success/60 bg-success/10 text-success",
|
|
166
|
+
active: "border-success bg-success/25 text-success ring-2 ring-success/40",
|
|
167
|
+
},
|
|
168
|
+
destructive: {
|
|
169
|
+
idle: "border-destructive/60 bg-destructive/10 text-destructive",
|
|
170
|
+
active: "border-destructive bg-destructive/25 text-destructive ring-2 ring-destructive/40",
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
function ActionZone({ id, label, regionLabel, icon: Icon, tone, visible, }) {
|
|
174
|
+
const { ref, isDropTarget } = useDroppable({
|
|
175
|
+
id,
|
|
176
|
+
type: "column",
|
|
177
|
+
accept: "item",
|
|
178
|
+
collisionPriority: ACTION_ZONE_PRIORITY,
|
|
179
|
+
disabled: !visible,
|
|
180
|
+
});
|
|
181
|
+
// A ring, not a scale, marks the target: scale clips in overflow parents.
|
|
182
|
+
return (_jsxs("div", { ref: ref, role: "region", "aria-label": regionLabel, "aria-hidden": !visible, "data-slot": "kanban-action-zone", "data-drop-target": isDropTarget || undefined, className: cn("relative z-10 flex flex-1 items-center justify-center gap-2 border-2 border-dashed p-3", "text-sm font-medium transition-[box-shadow,border-color,background-color,color] duration-150", visible ? "opacity-100" : "pointer-events-none opacity-0", isDropTarget ? zoneTone[tone].active : zoneTone[tone].idle), children: [_jsx(Icon, { className: "size-4 shrink-0", "aria-hidden": true }), label] }));
|
|
183
|
+
}
|
|
184
|
+
function ScrollButton({ side, onClick, }) {
|
|
185
|
+
const Icon = side === "start" ? ChevronLeft : ChevronRight;
|
|
186
|
+
return (_jsx(Button, { type: "button", variant: "outline", size: "icon-sm", "data-slot": "kanban-scroll-button", "aria-label": side === "start" ? "Show previous columns" : "Show next columns", onClick: onClick, className: cn("absolute top-1/2 z-20 -translate-y-1/2", side === "start" ? "left-1" : "right-1"), children: _jsx(Icon, {}) }));
|
|
187
|
+
}
|
|
188
|
+
function OverflowFade({ side, visible, }) {
|
|
189
|
+
return (_jsx("div", { "aria-hidden": true, "data-slot": "kanban-overflow-fade", "data-side": side, className: cn("pointer-events-none absolute inset-y-0 z-10 w-10 to-transparent transition-opacity", side === "start"
|
|
190
|
+
? "left-0 bg-gradient-to-r from-background"
|
|
191
|
+
: "right-0 bg-gradient-to-l from-background", visible ? "opacity-100" : "opacity-0") }));
|
|
192
|
+
}
|
|
193
|
+
/** Board-shaped placeholder for a route `loading` file. */
|
|
194
|
+
function KanbanSkeleton({ columnCount = 4, className, columnClassName, ...props }) {
|
|
195
|
+
return (_jsx("div", { "data-slot": "kanban-skeleton", className: cn("flex gap-4 overflow-hidden", className), ...props, children: Array.from({ length: columnCount }, (_, index) => (_jsx(Skeleton, { className: cn("shrink-0", columnSize, columnClassName) }, index))) }));
|
|
196
|
+
}
|
|
197
|
+
export { KanbanBoard, KanbanSkeleton };
|
package/dist/markdown.d.ts
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export declare function safeMarkdownUrl(url: string): string;
|
|
6
6
|
export type MarkdownProps = {
|
|
7
|
+
/** Markdown source to render. Raw HTML is dropped and unsafe URLs are removed. */
|
|
7
8
|
content: string;
|
|
9
|
+
/** Classes for the `article` wrapper. */
|
|
8
10
|
className?: string;
|
|
9
11
|
};
|
|
10
12
|
/**
|
package/dist/meter.d.ts
CHANGED
|
@@ -2,16 +2,23 @@ import type * as React from "react";
|
|
|
2
2
|
export type MeterMarker = {
|
|
3
3
|
/** Same scale as `value` / `min` / `max` (not a 0–1 fraction). */
|
|
4
4
|
position: number;
|
|
5
|
+
/** Classes for the tick, e.g. its color. */
|
|
5
6
|
className?: string;
|
|
6
7
|
};
|
|
7
8
|
export type MeterProps = Omit<React.ComponentProps<"div">, "children" | "role" | "aria-label"> & {
|
|
9
|
+
/** Current reading. Clamped to `min`–`max`; a non-finite value shows as empty. */
|
|
8
10
|
value: number;
|
|
11
|
+
/** Start of the scale. Default `0`. */
|
|
9
12
|
min?: number;
|
|
13
|
+
/** End of the scale. */
|
|
10
14
|
max: number;
|
|
11
15
|
/** App-owned fill (status, pace). Defaults to primary. */
|
|
12
16
|
fillClassName?: string;
|
|
17
|
+
/** Thin ticks drawn over the track, e.g. a cap or a typical value. */
|
|
13
18
|
markers?: MeterMarker[];
|
|
19
|
+
/** Required accessible name; the meter has no visible label. */
|
|
14
20
|
"aria-label": string;
|
|
21
|
+
/** Classes for the track. */
|
|
15
22
|
className?: string;
|
|
16
23
|
};
|
|
17
24
|
/**
|
package/dist/nav-link.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import type { AsChildProps } from "./internal/as-child.js";
|
|
2
3
|
/**
|
|
3
4
|
* Pill chrome for app-shell navigation. Inactive is muted text with an
|
|
4
5
|
* accent hover; active uses the shared selected wash, text, and border
|
|
@@ -6,17 +7,25 @@ import * as React from "react";
|
|
|
6
7
|
* Apps pass `active` — the kit has no router.
|
|
7
8
|
*/
|
|
8
9
|
declare const navLinkVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
10
|
+
/**
|
|
11
|
+
* Whether `href` is the current page for a nav link: the path itself, or a
|
|
12
|
+
* page under it (`/tasks` is active on `/tasks/42`, not on `/tasks-archive`).
|
|
13
|
+
* The kit has no router, so the app passes the pathname:
|
|
14
|
+
* `active={isNavActive(pathname, href)}`.
|
|
15
|
+
*/
|
|
16
|
+
declare function isNavActive(pathname: string, href: string): boolean;
|
|
9
17
|
/**
|
|
10
18
|
* Pill link for app-shell destinations (Calendar, Tasks, Settings). Pass
|
|
11
|
-
* `active` from the route
|
|
12
|
-
*
|
|
19
|
+
* `active` from the route (`isNavActive` compares a pathname with the
|
|
20
|
+
* link's `href`); the kit does not read the URL. `asChild` wraps a router
|
|
21
|
+
* `Link` with these styles, the same Slot pattern as `BreadcrumbLink`.
|
|
13
22
|
*
|
|
14
23
|
* Not a tab: in-page view switches that belong in the URL use `TabsNav`
|
|
15
|
-
* and `
|
|
24
|
+
* and `TabsNavLink`. Next apps can import the optional adapter
|
|
16
25
|
* from `atlas-react-kit/next/nav-link` instead of composing `asChild`.
|
|
17
26
|
*/
|
|
18
|
-
declare function NavLink({ asChild, active, className, ...props }: React.ComponentProps<"a"> & {
|
|
19
|
-
|
|
27
|
+
declare function NavLink({ asChild, active, className, ...props }: React.ComponentProps<"a"> & AsChildProps & {
|
|
28
|
+
/** This link is the current page: `aria-current="page"` and the selected chrome. */
|
|
20
29
|
active: boolean;
|
|
21
30
|
}): React.JSX.Element;
|
|
22
|
-
export { NavLink, navLinkVariants };
|
|
31
|
+
export { NavLink, isNavActive, navLinkVariants };
|
package/dist/nav-link.js
CHANGED
|
@@ -15,17 +15,27 @@ const navLinkVariants = cva([
|
|
|
15
15
|
selectedState.active,
|
|
16
16
|
"inline-flex items-center gap-1.5 rounded-none border border-transparent px-3 py-1.5 text-sm text-muted-foreground transition-colors hover:bg-accent data-[state=active]:font-medium",
|
|
17
17
|
]);
|
|
18
|
+
/**
|
|
19
|
+
* Whether `href` is the current page for a nav link: the path itself, or a
|
|
20
|
+
* page under it (`/tasks` is active on `/tasks/42`, not on `/tasks-archive`).
|
|
21
|
+
* The kit has no router, so the app passes the pathname:
|
|
22
|
+
* `active={isNavActive(pathname, href)}`.
|
|
23
|
+
*/
|
|
24
|
+
function isNavActive(pathname, href) {
|
|
25
|
+
return pathname === href || pathname.startsWith(`${href}/`);
|
|
26
|
+
}
|
|
18
27
|
/**
|
|
19
28
|
* Pill link for app-shell destinations (Calendar, Tasks, Settings). Pass
|
|
20
|
-
* `active` from the route
|
|
21
|
-
*
|
|
29
|
+
* `active` from the route (`isNavActive` compares a pathname with the
|
|
30
|
+
* link's `href`); the kit does not read the URL. `asChild` wraps a router
|
|
31
|
+
* `Link` with these styles, the same Slot pattern as `BreadcrumbLink`.
|
|
22
32
|
*
|
|
23
33
|
* Not a tab: in-page view switches that belong in the URL use `TabsNav`
|
|
24
|
-
* and `
|
|
34
|
+
* and `TabsNavLink`. Next apps can import the optional adapter
|
|
25
35
|
* from `atlas-react-kit/next/nav-link` instead of composing `asChild`.
|
|
26
36
|
*/
|
|
27
37
|
function NavLink({ asChild, active, className, ...props }) {
|
|
28
38
|
const Comp = asChild ? Slot.Root : "a";
|
|
29
39
|
return (_jsx(Comp, { "data-slot": "nav-link", "data-state": active ? "active" : "inactive", "aria-current": active ? "page" : undefined, className: cn(navLinkVariants(), className), ...props }));
|
|
30
40
|
}
|
|
31
|
-
export { NavLink, navLinkVariants };
|
|
41
|
+
export { NavLink, isNavActive, navLinkVariants };
|
package/dist/next/nav-link.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type * as React from "react";
|
|
2
2
|
import Link from "next/link.js";
|
|
3
3
|
/**
|
|
4
|
-
* Next.js adapter for the shell `NavLink` pill
|
|
5
|
-
* `
|
|
6
|
-
*
|
|
4
|
+
* Next.js adapter for the shell `NavLink` pill: the base `NavLink` with
|
|
5
|
+
* `asChild` around a Next `Link`, so it renders the same element. Same
|
|
6
|
+
* contract as `TabsNavLink`: Next `Link` props plus a required `active`
|
|
7
|
+
* boolean. The kit still does not read the router; the app passes `active`,
|
|
8
|
+
* usually `active={isNavActive(usePathname(), href)}` with `isNavActive`
|
|
9
|
+
* from `atlas-react-kit/nav-link`.
|
|
7
10
|
*/
|
|
8
11
|
declare function NavLink({ active, className, ...props }: React.ComponentProps<typeof Link> & {
|
|
9
12
|
active: boolean;
|
package/dist/next/nav-link.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import Link from "next/link.js";
|
|
4
|
-
import {
|
|
5
|
-
import { cn } from "../utils.js";
|
|
4
|
+
import { NavLink as BaseNavLink } from "../nav-link.js";
|
|
6
5
|
/**
|
|
7
|
-
* Next.js adapter for the shell `NavLink` pill
|
|
8
|
-
* `
|
|
9
|
-
*
|
|
6
|
+
* Next.js adapter for the shell `NavLink` pill: the base `NavLink` with
|
|
7
|
+
* `asChild` around a Next `Link`, so it renders the same element. Same
|
|
8
|
+
* contract as `TabsNavLink`: Next `Link` props plus a required `active`
|
|
9
|
+
* boolean. The kit still does not read the router; the app passes `active`,
|
|
10
|
+
* usually `active={isNavActive(usePathname(), href)}` with `isNavActive`
|
|
11
|
+
* from `atlas-react-kit/nav-link`.
|
|
10
12
|
*/
|
|
11
13
|
function NavLink({ active, className, ...props }) {
|
|
12
|
-
return (_jsx(
|
|
14
|
+
return (_jsx(BaseNavLink, { asChild: true, active: active, className: className, children: _jsx(Link, { ...props }) }));
|
|
13
15
|
}
|
|
14
16
|
export { NavLink };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type PeriodStepperFrameProps } from "../period-stepper.js";
|
|
2
|
+
/**
|
|
3
|
+
* Next.js `PeriodStepper`: each step is a prefetched link, so the period
|
|
4
|
+
* lives in the URL. Leave out `todayHref` to drop the Today link.
|
|
5
|
+
*/
|
|
6
|
+
declare function PeriodStepper({ previousHref, todayHref, nextHref, ...props }: PeriodStepperFrameProps & {
|
|
7
|
+
previousHref: string;
|
|
8
|
+
todayHref?: string;
|
|
9
|
+
nextHref: string;
|
|
10
|
+
}): import("react").JSX.Element;
|
|
11
|
+
export { PeriodStepper };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import Link from "next/link.js";
|
|
4
|
+
import { PeriodStepperFrame, } from "../period-stepper.js";
|
|
5
|
+
/**
|
|
6
|
+
* Next.js `PeriodStepper`: each step is a prefetched link, so the period
|
|
7
|
+
* lives in the URL. Leave out `todayHref` to drop the Today link.
|
|
8
|
+
*/
|
|
9
|
+
function PeriodStepper({ previousHref, todayHref, nextHref, ...props }) {
|
|
10
|
+
const hrefs = { previous: previousHref, today: todayHref, next: nextHref };
|
|
11
|
+
return (_jsx(PeriodStepperFrame, { ...props, control: (step, content) => {
|
|
12
|
+
const href = hrefs[step];
|
|
13
|
+
return href ? (_jsx(Link, { href: href, prefetch: true, children: content })) : null;
|
|
14
|
+
} }));
|
|
15
|
+
}
|
|
16
|
+
export { PeriodStepper };
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type * as React from "react";
|
|
2
2
|
import Link from "next/link.js";
|
|
3
|
+
/**
|
|
4
|
+
* Next.js adapter for `TabsNavLink`: the base link with `asChild` around a
|
|
5
|
+
* Next `Link`, so it renders the same element. Next `Link` props plus a
|
|
6
|
+
* required `active` boolean (`isNavActive(usePathname(), href)` from
|
|
7
|
+
* `atlas-react-kit/nav-link` works here too).
|
|
8
|
+
*/
|
|
3
9
|
declare function TabsNavLink({ active, className, ...props }: React.ComponentProps<typeof Link> & {
|
|
4
10
|
active: boolean;
|
|
5
11
|
}): React.JSX.Element;
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import Link from "next/link.js";
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import { TabsNavLink as BaseTabsNavLink } from "../tabs.js";
|
|
5
|
+
/**
|
|
6
|
+
* Next.js adapter for `TabsNavLink`: the base link with `asChild` around a
|
|
7
|
+
* Next `Link`, so it renders the same element. Next `Link` props plus a
|
|
8
|
+
* required `active` boolean (`isNavActive(usePathname(), href)` from
|
|
9
|
+
* `atlas-react-kit/nav-link` works here too).
|
|
10
|
+
*/
|
|
6
11
|
function TabsNavLink({ active, className, ...props }) {
|
|
7
|
-
return (_jsx(
|
|
12
|
+
return (_jsx(BaseTabsNavLink, { asChild: true, active: active, className: className, children: _jsx(Link, { ...props }) }));
|
|
8
13
|
}
|
|
9
14
|
export { TabsNavLink };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* A page's title row: the heading, an optional hint, anything else that
|
|
4
|
+
* belongs under them (badges, meta), and actions on the right. Stacks on
|
|
5
|
+
* small screens.
|
|
6
|
+
*/
|
|
7
|
+
declare function PageHeader({ title, description, actions, titleAs: Title, titleClassName, className, children, ...props }: {
|
|
8
|
+
/** The page heading. */
|
|
9
|
+
title: React.ReactNode;
|
|
10
|
+
/** Muted hint under the title. */
|
|
11
|
+
description?: React.ReactNode;
|
|
12
|
+
/** Buttons or links on the right (stacked below on small screens). */
|
|
13
|
+
actions?: React.ReactNode;
|
|
14
|
+
/** Heading level. Default `h1`. */
|
|
15
|
+
titleAs?: "h1" | "h2" | "h3";
|
|
16
|
+
/** Classes for the heading. */
|
|
17
|
+
titleClassName?: string;
|
|
18
|
+
} & Omit<React.ComponentProps<"header">, "title">): React.JSX.Element;
|
|
19
|
+
export { PageHeader };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "./utils.js";
|
|
3
|
+
/**
|
|
4
|
+
* A page's title row: the heading, an optional hint, anything else that
|
|
5
|
+
* belongs under them (badges, meta), and actions on the right. Stacks on
|
|
6
|
+
* small screens.
|
|
7
|
+
*/
|
|
8
|
+
function PageHeader({ title, description, actions, titleAs: Title = "h1", titleClassName, className, children, ...props }) {
|
|
9
|
+
return (_jsxs("header", { "data-slot": "page-header", className: cn("flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-start sm:justify-between", className), ...props, children: [_jsxs("div", { "data-slot": "page-header-heading", className: "flex min-w-0 flex-col gap-1", children: [_jsx(Title, { "data-slot": "page-header-title", className: cn("text-2xl font-semibold tracking-tight", titleClassName), children: title }), description ? (_jsx("p", { "data-slot": "page-header-description", className: "text-sm text-muted-foreground", children: description })) : null, children] }), actions ? (_jsx("div", { "data-slot": "page-header-actions", className: "flex flex-wrap items-center gap-2", children: actions })) : null] }));
|
|
10
|
+
}
|
|
11
|
+
export { PageHeader };
|
package/dist/pagination.d.ts
CHANGED
|
@@ -9,7 +9,9 @@ declare function Pagination({ className, ...props }: React.ComponentProps<"nav">
|
|
|
9
9
|
declare function PaginationContent({ className, ...props }: React.ComponentProps<"ul">): React.JSX.Element;
|
|
10
10
|
declare function PaginationItem({ ...props }: React.ComponentProps<"li">): React.JSX.Element;
|
|
11
11
|
type PaginationLinkProps = {
|
|
12
|
+
/** This link is the current page: `aria-current="page"` and the selected wash. */
|
|
12
13
|
isActive?: boolean;
|
|
14
|
+
/** `icon` (default) is a square page number; `default` fits text such as Previous. */
|
|
13
15
|
size?: "default" | "icon";
|
|
14
16
|
/**
|
|
15
17
|
* No page to go to, such as Previous on the first page. Renders without
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
type PeriodStepperFrameProps = {
|
|
3
|
+
/** The range shown, announced when it changes. */
|
|
4
|
+
label: React.ReactNode;
|
|
5
|
+
/** What one step moves ("month", "week"), for the button names. */
|
|
6
|
+
stepLabel: string;
|
|
7
|
+
/** Classes for the range heading. */
|
|
8
|
+
labelClassName?: string;
|
|
9
|
+
} & Omit<React.ComponentProps<"div">, "children">;
|
|
10
|
+
/**
|
|
11
|
+
* Layout under both steppers. `control` renders each step as the element a
|
|
12
|
+
* `Button` wraps (`asChild`), such as another router's link; returning
|
|
13
|
+
* `null` for "today" drops that button.
|
|
14
|
+
*/
|
|
15
|
+
declare function PeriodStepperFrame({ label, stepLabel, labelClassName, className, control, ...props }: PeriodStepperFrameProps & {
|
|
16
|
+
/** Renders the element for each step; return `null` for "today" to drop it. */
|
|
17
|
+
control: (step: "previous" | "today" | "next", content: React.ReactNode) => React.ReactElement | null;
|
|
18
|
+
}): React.JSX.Element;
|
|
19
|
+
/**
|
|
20
|
+
* Previous / Today / Next buttons and the range they show (a month, a
|
|
21
|
+
* week). The app owns the period; for URL-driven periods in Next use
|
|
22
|
+
* `next/period-stepper`. Leave out `onToday` to drop the Today button.
|
|
23
|
+
*/
|
|
24
|
+
declare function PeriodStepper({ onPrevious, onToday, onNext, ...props }: PeriodStepperFrameProps & {
|
|
25
|
+
/** Called when Previous is pressed. */
|
|
26
|
+
onPrevious: () => void;
|
|
27
|
+
/** Called when Today is pressed. Leave out to drop the Today button. */
|
|
28
|
+
onToday?: () => void;
|
|
29
|
+
/** Called when Next is pressed. */
|
|
30
|
+
onNext: () => void;
|
|
31
|
+
}): React.JSX.Element;
|
|
32
|
+
export { PeriodStepper, PeriodStepperFrame, type PeriodStepperFrameProps };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
4
|
+
import { Button } from "./button.js";
|
|
5
|
+
import { cn } from "./utils.js";
|
|
6
|
+
/**
|
|
7
|
+
* Layout under both steppers. `control` renders each step as the element a
|
|
8
|
+
* `Button` wraps (`asChild`), such as another router's link; returning
|
|
9
|
+
* `null` for "today" drops that button.
|
|
10
|
+
*/
|
|
11
|
+
function PeriodStepperFrame({ label, stepLabel, labelClassName, className, control, ...props }) {
|
|
12
|
+
const today = control("today", "Today");
|
|
13
|
+
return (_jsxs("div", { "data-slot": "period-stepper", className: cn("flex flex-wrap items-center gap-2", className), ...props, children: [_jsx(Button, { variant: "outline", size: "icon-sm", "aria-label": `Previous ${stepLabel}`, asChild: true, children: control("previous", _jsx(ChevronLeft, {})) }), today ? (_jsx(Button, { variant: "outline", size: "sm", asChild: true, children: today })) : null, _jsx(Button, { variant: "outline", size: "icon-sm", "aria-label": `Next ${stepLabel}`, asChild: true, children: control("next", _jsx(ChevronRight, {})) }), _jsx("h2", { "aria-live": "polite", "data-slot": "period-stepper-label", className: cn("text-base font-semibold tabular-nums", labelClassName), children: label })] }));
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Previous / Today / Next buttons and the range they show (a month, a
|
|
17
|
+
* week). The app owns the period; for URL-driven periods in Next use
|
|
18
|
+
* `next/period-stepper`. Leave out `onToday` to drop the Today button.
|
|
19
|
+
*/
|
|
20
|
+
function PeriodStepper({ onPrevious, onToday, onNext, ...props }) {
|
|
21
|
+
const handlers = { previous: onPrevious, today: onToday, next: onNext };
|
|
22
|
+
return (_jsx(PeriodStepperFrame, { ...props, control: (step, content) => {
|
|
23
|
+
const onClick = handlers[step];
|
|
24
|
+
return onClick ? (_jsx("button", { type: "button", onClick: onClick, children: content })) : null;
|
|
25
|
+
} }));
|
|
26
|
+
}
|
|
27
|
+
export { PeriodStepper, PeriodStepperFrame };
|
package/dist/picker-shell.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import type { Locale } from "date-fns";
|
|
3
3
|
import { type DateLike, type DateMatcher } from "./internal/date-like.js";
|
|
4
|
+
import { LazyCalendar } from "./lazy-calendar.js";
|
|
4
5
|
import { PopoverContent } from "./popover.js";
|
|
5
6
|
/**
|
|
6
|
-
* Not a public entry. The trigger, popover, and Clear
|
|
7
|
-
* `DatePickerButton` and `DateTimePickerButton` share.
|
|
7
|
+
* Not a public entry. The trigger, popover, calendar wiring, and Clear row
|
|
8
|
+
* that `DatePickerButton` and `DateTimePickerButton` share.
|
|
8
9
|
*/
|
|
9
10
|
/**
|
|
10
11
|
* Options for the picker's calendar. The picker owns the selection, focus,
|
|
@@ -39,13 +40,20 @@ export type PickerCalendarProps = {
|
|
|
39
40
|
};
|
|
40
41
|
/** Props both pickers take for their trigger and popover. */
|
|
41
42
|
export type PickerTriggerProps = {
|
|
43
|
+
/** Id of the trigger button; the trigger text gets `${id}-value`. */
|
|
42
44
|
id?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Trigger text while nothing is picked. Defaults to "Pick a date", "Pick a
|
|
47
|
+
* date range", or "Pick a date and time" depending on the picker.
|
|
48
|
+
*/
|
|
43
49
|
placeholder?: string;
|
|
50
|
+
/** Disable the trigger so the popover cannot open. */
|
|
44
51
|
disabled?: boolean;
|
|
45
52
|
/** Classes for the trigger button. */
|
|
46
53
|
className?: string;
|
|
47
54
|
/** Classes for the popover content, e.g. a width such as `w-80`. */
|
|
48
55
|
contentClassName?: string;
|
|
56
|
+
/** Mark the trigger invalid, e.g. when its field has an error. */
|
|
49
57
|
"aria-invalid"?: boolean;
|
|
50
58
|
/**
|
|
51
59
|
* Forwarded to the trigger. To name it from a visible label while still
|
|
@@ -73,29 +81,36 @@ export type PickerTriggerProps = {
|
|
|
73
81
|
/** Day Picker options passed through to the calendar. */
|
|
74
82
|
calendarProps?: PickerCalendarProps;
|
|
75
83
|
};
|
|
76
|
-
|
|
77
|
-
* `calendarProps` with `minDate` / `maxDate` applied: days outside them join
|
|
78
|
-
* any `disabled` matchers, and they bound paging unless `startMonth` /
|
|
79
|
-
* `endMonth` are set.
|
|
80
|
-
*/
|
|
81
|
-
export declare function limitCalendarProps(calendarProps: PickerCalendarProps | undefined, minDate: DateLike, maxDate: DateLike): PickerCalendarProps | undefined;
|
|
82
|
-
type PickerShellProps = Omit<PickerTriggerProps, "placeholder" | "defaultMonth" | "calendarProps" | "minDate" | "maxDate"> & {
|
|
84
|
+
type PickerShellProps = Omit<PickerTriggerProps, "placeholder"> & {
|
|
83
85
|
/** Muted trigger text while nothing is picked. */
|
|
84
86
|
empty: boolean;
|
|
85
87
|
/** Trigger text: the formatted value or the placeholder. */
|
|
86
88
|
label: string;
|
|
87
89
|
/** Accessible name of the popover dialog. */
|
|
88
90
|
dialogLabel: string;
|
|
91
|
+
/** Whether the popover is open. */
|
|
89
92
|
open: boolean;
|
|
93
|
+
/** Called when the popover opens or closes. */
|
|
90
94
|
onOpenChange: (open: boolean) => void;
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
/**
|
|
96
|
+
* The picker's own calendar props: its mode, selection and `onSelect`.
|
|
97
|
+
* The shell adds `calendarProps`, the date limits, `defaultMonth`, and
|
|
98
|
+
* focus on the selected day.
|
|
99
|
+
*/
|
|
100
|
+
calendar: React.ComponentProps<typeof LazyCalendar>;
|
|
101
|
+
/**
|
|
102
|
+
* Shows a Clear row under the panel. Called when Clear is pressed; the
|
|
103
|
+
* popover then closes.
|
|
104
|
+
*/
|
|
105
|
+
onClear?: () => void;
|
|
106
|
+
/** Disable Clear, e.g. while nothing is picked. */
|
|
107
|
+
clearDisabled?: boolean;
|
|
108
|
+
/** Extra panel rows between the calendar and Clear, e.g. time selects. */
|
|
109
|
+
children?: React.ReactNode;
|
|
93
110
|
};
|
|
94
|
-
/**
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
onClear: () => void;
|
|
100
|
-
}): React.JSX.Element;
|
|
111
|
+
/**
|
|
112
|
+
* Form-control trigger plus the viewport-clamped popover holding the
|
|
113
|
+
* calendar, any extra rows, and an optional Clear row.
|
|
114
|
+
*/
|
|
115
|
+
export declare function PickerShell({ id, disabled, className, contentClassName, "aria-invalid": ariaInvalid, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, side, defaultMonth, minDate, maxDate, calendarProps, empty, label, dialogLabel, open, onOpenChange, calendar, onClear, clearDisabled, children, }: PickerShellProps): React.JSX.Element;
|
|
101
116
|
export {};
|