atlas-react-kit 0.13.0 → 1.0.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 +118 -98
- package/DESIGN_RULES.md +30 -0
- package/README.md +10 -9
- 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 +14 -2
- package/dist/date-picker.js +12 -19
- package/dist/date-time-picker.d.ts +5 -2
- package/dist/date-time-picker.js +6 -5
- 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 +6 -20
- package/dist/form/date-picker-field.js +2 -2
- package/dist/form/date-time-picker-field.d.ts +6 -21
- package/dist/form/date-time-picker-field.js +1 -1
- package/dist/form/feedback-field.d.ts +2 -0
- package/dist/form/field-error.d.ts +31 -0
- package/dist/form/field-shell.d.ts +29 -1
- package/dist/form/markdown-field.d.ts +4 -16
- package/dist/form/select-field.d.ts +6 -6
- 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/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 +3 -2
- package/dist/next/period-stepper.d.ts +11 -0
- package/dist/next/period-stepper.js +16 -0
- 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 +12 -0
- package/dist/picker-shell.js +1 -1
- 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 +9 -5
- package/dist/tabs.js +1 -1
- 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 +69 -7
- package/theme.css +11 -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
|
|
@@ -15,8 +16,8 @@ declare const navLinkVariants: (props?: import("class-variance-authority/types")
|
|
|
15
16
|
* and `tabsTriggerVariants()`. Next apps can import the optional adapter
|
|
16
17
|
* from `atlas-react-kit/next/nav-link` instead of composing `asChild`.
|
|
17
18
|
*/
|
|
18
|
-
declare function NavLink({ asChild, active, className, ...props }: React.ComponentProps<"a"> & {
|
|
19
|
-
|
|
19
|
+
declare function NavLink({ asChild, active, className, ...props }: React.ComponentProps<"a"> & AsChildProps & {
|
|
20
|
+
/** This link is the current page: `aria-current="page"` and the selected chrome. */
|
|
20
21
|
active: boolean;
|
|
21
22
|
}): React.JSX.Element;
|
|
22
23
|
export { NavLink, navLinkVariants };
|
|
@@ -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 };
|
|
@@ -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
|
@@ -39,13 +39,20 @@ export type PickerCalendarProps = {
|
|
|
39
39
|
};
|
|
40
40
|
/** Props both pickers take for their trigger and popover. */
|
|
41
41
|
export type PickerTriggerProps = {
|
|
42
|
+
/** Id of the trigger button; the trigger text gets `${id}-value`. */
|
|
42
43
|
id?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Trigger text while nothing is picked. Defaults to "Pick a date", "Pick a
|
|
46
|
+
* date range", or "Pick a date and time" depending on the picker.
|
|
47
|
+
*/
|
|
43
48
|
placeholder?: string;
|
|
49
|
+
/** Disable the trigger so the popover cannot open. */
|
|
44
50
|
disabled?: boolean;
|
|
45
51
|
/** Classes for the trigger button. */
|
|
46
52
|
className?: string;
|
|
47
53
|
/** Classes for the popover content, e.g. a width such as `w-80`. */
|
|
48
54
|
contentClassName?: string;
|
|
55
|
+
/** Mark the trigger invalid, e.g. when its field has an error. */
|
|
49
56
|
"aria-invalid"?: boolean;
|
|
50
57
|
/**
|
|
51
58
|
* Forwarded to the trigger. To name it from a visible label while still
|
|
@@ -86,8 +93,11 @@ type PickerShellProps = Omit<PickerTriggerProps, "placeholder" | "defaultMonth"
|
|
|
86
93
|
label: string;
|
|
87
94
|
/** Accessible name of the popover dialog. */
|
|
88
95
|
dialogLabel: string;
|
|
96
|
+
/** Whether the popover is open. */
|
|
89
97
|
open: boolean;
|
|
98
|
+
/** Called when the popover opens or closes. */
|
|
90
99
|
onOpenChange: (open: boolean) => void;
|
|
100
|
+
/** Called on a pointer down or focus outside the popover; can prevent the dismiss. */
|
|
91
101
|
onInteractOutside?: React.ComponentProps<typeof PopoverContent>["onInteractOutside"];
|
|
92
102
|
children: React.ReactNode;
|
|
93
103
|
};
|
|
@@ -95,7 +105,9 @@ type PickerShellProps = Omit<PickerTriggerProps, "placeholder" | "defaultMonth"
|
|
|
95
105
|
export declare function PickerShell({ id, disabled, className, contentClassName, "aria-invalid": ariaInvalid, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, side, empty, label, dialogLabel, open, onOpenChange, onInteractOutside, children, }: PickerShellProps): React.JSX.Element;
|
|
96
106
|
/** Clear button row under the calendar. */
|
|
97
107
|
export declare function PickerClearFooter({ disabled, onClear, }: {
|
|
108
|
+
/** Disable the Clear button, e.g. while nothing is picked. */
|
|
98
109
|
disabled: boolean;
|
|
110
|
+
/** Called when Clear is pressed. */
|
|
99
111
|
onClear: () => void;
|
|
100
112
|
}): React.JSX.Element;
|
|
101
113
|
export {};
|
package/dist/picker-shell.js
CHANGED
|
@@ -37,7 +37,7 @@ export function limitCalendarProps(calendarProps, minDate, maxDate) {
|
|
|
37
37
|
}
|
|
38
38
|
/** Form-control trigger plus the viewport-clamped calendar popover. */
|
|
39
39
|
export function PickerShell({ id, disabled, className, contentClassName, "aria-invalid": ariaInvalid, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, side, empty, label, dialogLabel, open, onOpenChange, onInteractOutside, children, }) {
|
|
40
|
-
return (_jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { id: id, type: "button", variant: "outline", disabled: disabled, "aria-invalid": ariaInvalid, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, "data-empty": empty, className: cn(pickerTriggerClassName, className), onPointerEnter: preloadCalendar, onFocus: preloadCalendar, children: [_jsx(CalendarIcon, { "data-icon": "inline-start" }), _jsx("span", { "data-slot": "date-picker-value", id: id ? pickerValueId(id) : undefined, children: label })] }) }), _jsx(PopoverContent, { align: "start", side: side, collisionPadding: PICKER_COLLISION_PADDING, "aria-label": dialogLabel,
|
|
40
|
+
return (_jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { id: id, type: "button", variant: "outline", disabled: disabled, "aria-invalid": ariaInvalid, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, "data-empty": empty, className: cn(pickerTriggerClassName, className), onPointerEnter: preloadCalendar, onFocus: preloadCalendar, children: [_jsx(CalendarIcon, { "data-icon": "inline-start" }), _jsx("span", { "data-slot": "date-picker-value", className: "min-w-0 text-left whitespace-normal", id: id ? pickerValueId(id) : undefined, children: label })] }) }), _jsx(PopoverContent, { align: "start", side: side, collisionPadding: PICKER_COLLISION_PADDING, "aria-label": dialogLabel,
|
|
41
41
|
// The calendar's `autoFocus` puts focus on the selected day (or
|
|
42
42
|
// today) once it loads, as the APG date picker dialog does; Radix
|
|
43
43
|
// focusing the popover first would leave it on the container.
|
package/dist/progress.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { Progress as ProgressPrimitive } from "radix-ui";
|
|
|
7
7
|
* label. `indicatorClassName` styles the fill (default `bg-primary`).
|
|
8
8
|
*/
|
|
9
9
|
declare function Progress({ className, indicatorClassName, value, max, ...props }: React.ComponentProps<typeof ProgressPrimitive.Root> & {
|
|
10
|
+
/** Classes for the fill, e.g. a status color. Defaults to `bg-primary`. */
|
|
10
11
|
indicatorClassName?: string;
|
|
11
12
|
}): React.JSX.Element;
|
|
12
13
|
export { Progress };
|
package/dist/search-picker.d.ts
CHANGED
|
@@ -6,17 +6,29 @@ export { foldSearchText };
|
|
|
6
6
|
*/
|
|
7
7
|
export declare function defaultSearchFilter<T>(item: T, query: string, getLabel: (item: T) => string): boolean;
|
|
8
8
|
export type SearchPickerProps<T> = {
|
|
9
|
+
/** Every choice, in display order. */
|
|
9
10
|
items: T[];
|
|
11
|
+
/** A unique, stable value for an item; matched against `value`. */
|
|
10
12
|
getValue: (item: T) => string;
|
|
13
|
+
/** The item's visible text, also what the default filter searches. */
|
|
11
14
|
getLabel: (item: T) => string;
|
|
15
|
+
/** Whether an item matches the query. Default `defaultSearchFilter` (label contains query, ignoring case and accents). */
|
|
12
16
|
filter?: (item: T, query: string, getLabel: (item: T) => string) => boolean;
|
|
17
|
+
/** The selected item's value, marked in the list. */
|
|
13
18
|
value?: string;
|
|
19
|
+
/** Called with the item picked by click or Enter; the query then clears. */
|
|
14
20
|
onSelect: (item: T) => void;
|
|
21
|
+
/** Visible label for the search input. */
|
|
15
22
|
label: string;
|
|
23
|
+
/** Placeholder for the search input. Default `"Search"`. */
|
|
16
24
|
placeholder?: string;
|
|
25
|
+
/** Text shown when nothing matches the query. Default `"No results"`. */
|
|
17
26
|
emptyText?: string;
|
|
27
|
+
/** Accessible name for the listbox. Defaults to `label`. */
|
|
18
28
|
listLabel?: string;
|
|
29
|
+
/** Disables the input and every option. */
|
|
19
30
|
disabled?: boolean;
|
|
31
|
+
/** Classes for the wrapper, e.g. its width. */
|
|
20
32
|
className?: string;
|
|
21
33
|
/** Classes for the listbox, e.g. its height. Defaults to `max-h-60`. */
|
|
22
34
|
listClassName?: string;
|
package/dist/select.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ declare function Select({ ...props }: React.ComponentProps<typeof SelectPrimitiv
|
|
|
4
4
|
declare function SelectGroup({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Group>): React.JSX.Element;
|
|
5
5
|
declare function SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.Value>): React.JSX.Element;
|
|
6
6
|
declare function SelectTrigger({ className, size, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
|
7
|
+
/** Trigger height: `default` (`h-10`) or `sm` (`h-9`). Default `default`. */
|
|
7
8
|
size?: "sm" | "default";
|
|
8
9
|
}): React.JSX.Element;
|
|
9
10
|
declare function SelectContent({ className, children, position, align, sideOffset, collisionPadding, ...props }: React.ComponentProps<typeof SelectPrimitive.Content>): React.JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* First focusable link on the page: hidden until a keyboard user tabs to
|
|
4
|
+
* it, then it jumps past the navigation to `href` (the main landmark's id).
|
|
5
|
+
*/
|
|
6
|
+
declare function SkipLink({ href, className, children, ...props }: React.ComponentProps<"a">): React.JSX.Element;
|
|
7
|
+
export { SkipLink };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "./utils.js";
|
|
3
|
+
/**
|
|
4
|
+
* First focusable link on the page: hidden until a keyboard user tabs to
|
|
5
|
+
* it, then it jumps past the navigation to `href` (the main landmark's id).
|
|
6
|
+
*/
|
|
7
|
+
function SkipLink({ href = "#main-content", className, children = "Skip to content", ...props }) {
|
|
8
|
+
return (_jsx("a", { "data-slot": "skip-link", href: href, className: cn("sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:bg-background focus:px-3 focus:py-2 focus:text-sm focus:ring-2 focus:ring-ring", className), ...props, children: children }));
|
|
9
|
+
}
|
|
10
|
+
export { SkipLink };
|
package/dist/slider.d.ts
CHANGED
|
@@ -1,18 +1,29 @@
|
|
|
1
1
|
import type * as React from "react";
|
|
2
2
|
import { Slider as SliderPrimitive } from "radix-ui";
|
|
3
3
|
export type SliderProps = Omit<React.ComponentProps<typeof SliderPrimitive.Root>, "value" | "defaultValue" | "onValueChange" | "onValueCommit" | "children"> & {
|
|
4
|
+
/** The current value; the slider is always controlled. */
|
|
4
5
|
value: number;
|
|
6
|
+
/** Called with the new value on every move while dragging or on a key press. */
|
|
5
7
|
onValueChange: (value: number) => void;
|
|
8
|
+
/** Called with the final value when a drag ends or a key press settles. */
|
|
6
9
|
onValueCommit?: (value: number) => void;
|
|
10
|
+
/** The lowest value. Default 0. */
|
|
7
11
|
min?: number;
|
|
12
|
+
/** The highest value. Default 100. */
|
|
8
13
|
max?: number;
|
|
14
|
+
/** The amount each move snaps to. Default 1. */
|
|
9
15
|
step?: number;
|
|
16
|
+
/** Dims the slider and ignores pointer and keyboard input. */
|
|
10
17
|
disabled?: boolean;
|
|
11
18
|
/** Goes on the thumb, so a `<Label htmlFor>` names the slider. */
|
|
12
19
|
id?: string;
|
|
20
|
+
/** Form field name, so the value submits with a surrounding `<form>`. */
|
|
13
21
|
name?: string;
|
|
22
|
+
/** Classes for the root, e.g. its width. */
|
|
14
23
|
className?: string;
|
|
24
|
+
/** Names the slider when there is no `<Label htmlFor={id}>`. Goes on the thumb. */
|
|
15
25
|
"aria-label"?: string;
|
|
26
|
+
/** Id of the element that names the slider. Goes on the thumb. */
|
|
16
27
|
"aria-labelledby"?: string;
|
|
17
28
|
};
|
|
18
29
|
/**
|
|
@@ -4,7 +4,9 @@ export type SortDirection = "asc" | "desc";
|
|
|
4
4
|
type SortableTableHeadProps = ComponentProps<typeof TableHead> & {
|
|
5
5
|
/** Whether this column is the active sort key. */
|
|
6
6
|
sorted?: boolean;
|
|
7
|
+
/** Sort order shown while `sorted`. Default `asc`. */
|
|
7
8
|
direction?: SortDirection;
|
|
9
|
+
/** Called when the header button is pressed, e.g. to toggle the sort. */
|
|
8
10
|
onClick?: () => void;
|
|
9
11
|
/** Classes for the inner sort button (`data-slot="sortable-table-head-button"`). */
|
|
10
12
|
buttonClassName?: string;
|
package/dist/stat-tile.d.ts
CHANGED
|
@@ -8,10 +8,15 @@ export { sectionLabel };
|
|
|
8
8
|
/** Row of tiles: stacked on phones, divided columns from `sm`. */
|
|
9
9
|
export declare const statTileGrid = "grid ring-1 ring-foreground/5 sm:divide-x";
|
|
10
10
|
export type StatTileProps = Omit<React.ComponentProps<"div">, "children" | "title"> & {
|
|
11
|
+
/** Small uppercase label above the figure. */
|
|
11
12
|
label: string;
|
|
13
|
+
/** The big figure, already formatted. */
|
|
12
14
|
value: string;
|
|
15
|
+
/** Muted line under the figure; hidden when empty. */
|
|
13
16
|
sub?: React.ReactNode;
|
|
17
|
+
/** Extra content between the figure and `sub`, e.g. a `Meter`. */
|
|
14
18
|
children?: React.ReactNode;
|
|
19
|
+
/** Classes for the root `div`. */
|
|
15
20
|
className?: string;
|
|
16
21
|
};
|
|
17
22
|
/**
|
package/dist/table.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ import * as React from "react";
|
|
|
11
11
|
* cap (`max-h-96 overflow-y-auto`) or a border.
|
|
12
12
|
*/
|
|
13
13
|
declare function Table({ className, containerClassName, ...props }: React.ComponentProps<"table"> & {
|
|
14
|
+
/** Classes for the scroller around the table, e.g. a height cap or border. */
|
|
14
15
|
containerClassName?: string;
|
|
15
16
|
}): React.JSX.Element;
|
|
16
17
|
declare function TableHeader({ className, ...props }: React.ComponentProps<"thead">): React.JSX.Element;
|