cortena-ui 1.2.0 → 1.3.1
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/README.md +34 -0
- package/dist/index.d.ts +253 -55
- package/dist/index.js +441 -86
- package/dist/index.js.map +1 -1
- package/package.json +4 -11
- package/src/a2ui/catalogue.ts +11 -2
- package/src/components/alert.tsx +9 -2
- package/src/components/badge.tsx +9 -4
- package/src/components/breadcrumb.tsx +171 -0
- package/src/components/button-link.tsx +3 -10
- package/src/components/card.tsx +27 -9
- package/src/components/chart/chart.tsx +54 -10
- package/src/components/chart/container.tsx +33 -2
- package/src/components/chart/data.ts +25 -1
- package/src/components/chart/index.tsx +1 -0
- package/src/components/chart/nivo-charts.tsx +45 -16
- package/src/components/chart/types.ts +19 -2
- package/src/components/data-table/data-table.tsx +23 -1
- package/src/components/data-table/export.ts +18 -2
- package/src/components/data-table/use-server-source.ts +17 -4
- package/src/components/dropzone.tsx +35 -1
- package/src/components/section-card.tsx +4 -0
- package/src/components/select.tsx +30 -1
- package/src/components/sheet.tsx +40 -4
- package/src/components/sortable-list.tsx +77 -9
- package/src/components/spinner.tsx +21 -4
- package/src/components/status-dot.tsx +14 -1
- package/src/index.ts +5 -3
- package/src/lib/render.tsx +39 -0
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { clsx } from "clsx";
|
|
3
3
|
import { twMerge } from "tailwind-merge";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import { AlertTriangle, ArrowDown, ArrowUp, CalendarIcon, Check, CheckCircle2, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, ChevronsLeft, ChevronsRight, ChevronsUpDown, Circle, Copy, Download, EyeOff, FileIcon, GripVertical, Inbox, Info, ListFilter, Minus, OctagonAlert, PinOff, RefreshCw, Search, Settings2, Terminal, Upload, X } from "lucide-react";
|
|
5
|
+
import { AlertTriangle, ArrowDown, ArrowUp, CalendarIcon, Check, CheckCircle2, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, ChevronsLeft, ChevronsRight, ChevronsUpDown, Circle, Copy, Download, EyeOff, FileIcon, GripVertical, Inbox, Info, ListFilter, Minus, MoreHorizontal, OctagonAlert, PinOff, RefreshCw, Search, Settings2, Terminal, Upload, X } from "lucide-react";
|
|
6
6
|
import * as React from "react";
|
|
7
7
|
import { createContext, useCallback, useContext, useEffect, useMemo, useState, useSyncExternalStore } from "react";
|
|
8
8
|
import { cva } from "class-variance-authority";
|
|
@@ -39,7 +39,7 @@ import { useRender } from "@base-ui/react/use-render";
|
|
|
39
39
|
import { Controller, FormProvider, useForm, useFormContext, useFormState } from "react-hook-form";
|
|
40
40
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
41
41
|
import { ScrollArea as ScrollArea$1 } from "@base-ui/react/scroll-area";
|
|
42
|
-
import { DndContext, DragOverlay, KeyboardSensor, PointerSensor, closestCenter, useSensor, useSensors } from "@dnd-kit/core";
|
|
42
|
+
import { DndContext, DragOverlay, KeyboardSensor, MouseSensor, PointerSensor, TouchSensor, closestCenter, useSensor, useSensors } from "@dnd-kit/core";
|
|
43
43
|
import { SortableContext, arrayMove, horizontalListSortingStrategy, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";
|
|
44
44
|
import { CSS } from "@dnd-kit/utilities";
|
|
45
45
|
import { Toast as Toast$1 } from "@base-ui/react/toast";
|
|
@@ -58,7 +58,11 @@ function cn(...inputs) {
|
|
|
58
58
|
* Alert — an inline callout. Tinted variants use the `-soft` fill for the
|
|
59
59
|
* background and the tone colour for the border and icon; the body text stays
|
|
60
60
|
* on the foreground token so it reads in both themes.
|
|
61
|
+
*
|
|
62
|
+
* The error tone is `destructive`, the same spelling Button uses; `danger` is
|
|
63
|
+
* a deprecated alias of it and paints identically.
|
|
61
64
|
*/
|
|
65
|
+
const DESTRUCTIVE_ALERT = "bg-[var(--ds-destructive-soft)] border-[var(--ds-destructive)]/35 [&_[data-slot=alert-icon]]:text-[color:var(--ds-destructive)]";
|
|
62
66
|
const alertVariants = cva([
|
|
63
67
|
"flex gap-3 rounded-[var(--ds-radius-md)] border px-3.5 py-3",
|
|
64
68
|
"text-[length:var(--ds-text-caption-lg)] leading-[var(--ds-text-caption-lg--line-height)]",
|
|
@@ -68,7 +72,9 @@ const alertVariants = cva([
|
|
|
68
72
|
default: "bg-[var(--ds-card)] border-[var(--ds-border-subtle)] [&_[data-slot=alert-icon]]:text-[color:var(--ds-muted-foreground)]",
|
|
69
73
|
success: "bg-[var(--ds-success-soft)] border-[var(--ds-success)]/35 [&_[data-slot=alert-icon]]:text-[color:var(--ds-success)]",
|
|
70
74
|
warn: "bg-[var(--ds-warning-soft)] border-[var(--ds-warning)]/35 [&_[data-slot=alert-icon]]:text-[color:var(--ds-warning)]",
|
|
71
|
-
|
|
75
|
+
destructive: DESTRUCTIVE_ALERT,
|
|
76
|
+
/** @deprecated Use `destructive`, the name Button and Badge use; this alias paints the same. */
|
|
77
|
+
danger: DESTRUCTIVE_ALERT,
|
|
72
78
|
info: "bg-[var(--ds-info-soft)] border-[var(--ds-info)]/35 [&_[data-slot=alert-icon]]:text-[color:var(--ds-info)]"
|
|
73
79
|
} },
|
|
74
80
|
defaultVariants: { variant: "default" }
|
|
@@ -106,9 +112,11 @@ function AlertDescription({ className, ...props }) {
|
|
|
106
112
|
//#region src/components/badge.tsx
|
|
107
113
|
/**
|
|
108
114
|
* Badge — the mono, uppercase status label. Each tone pairs a `-soft` fill
|
|
109
|
-
* with its foreground token
|
|
110
|
-
*
|
|
115
|
+
* with its foreground token. The error tone is `destructive`, the same
|
|
116
|
+
* spelling Button and Alert use; `warn`, `danger` and `secondary` are
|
|
117
|
+
* deprecated aliases kept for cortenaweb call sites and paint identically.
|
|
111
118
|
*/
|
|
119
|
+
const DESTRUCTIVE_BADGE = "bg-[var(--ds-destructive-soft)] text-[color:var(--ds-destructive)]";
|
|
112
120
|
const badgeVariants = cva([
|
|
113
121
|
"inline-flex items-center gap-1.5 px-1.5 py-0.5 whitespace-nowrap",
|
|
114
122
|
"rounded-[var(--ds-radius-sm)]",
|
|
@@ -120,9 +128,11 @@ const badgeVariants = cva([
|
|
|
120
128
|
default: "bg-[var(--ds-primary-soft)] text-[color:var(--ds-primary-soft-foreground)]",
|
|
121
129
|
success: "bg-[var(--ds-success-soft)] text-[color:var(--ds-success)]",
|
|
122
130
|
warning: "bg-[var(--ds-warning-soft)] text-[color:var(--ds-warning)]",
|
|
131
|
+
/** @deprecated Use `warning`; this alias paints the same. */
|
|
123
132
|
warn: "bg-[var(--ds-warning-soft)] text-[color:var(--ds-warning)]",
|
|
124
|
-
|
|
125
|
-
|
|
133
|
+
destructive: DESTRUCTIVE_BADGE,
|
|
134
|
+
/** @deprecated Use `destructive`, the name Button and Alert use; this alias paints the same. */
|
|
135
|
+
danger: DESTRUCTIVE_BADGE,
|
|
126
136
|
info: "bg-[var(--ds-info-soft)] text-[color:var(--ds-info)]",
|
|
127
137
|
neutral: "bg-[var(--ds-hover)] text-[color:var(--ds-muted-foreground)]",
|
|
128
138
|
secondary: "bg-[var(--ds-hover)] text-[color:var(--ds-muted-foreground)]",
|
|
@@ -194,41 +204,48 @@ function Button({ className, variant, size, ...props }) {
|
|
|
194
204
|
});
|
|
195
205
|
}
|
|
196
206
|
//#endregion
|
|
207
|
+
//#region src/lib/render.tsx
|
|
208
|
+
function renderWith(render, props, children, Fallback) {
|
|
209
|
+
if (!render) return /* @__PURE__ */ jsx(Fallback, {
|
|
210
|
+
...props,
|
|
211
|
+
children
|
|
212
|
+
});
|
|
213
|
+
const Element = render.type;
|
|
214
|
+
const given = render.props;
|
|
215
|
+
return /* @__PURE__ */ jsx(Element, {
|
|
216
|
+
...render.props,
|
|
217
|
+
...props,
|
|
218
|
+
children: children ?? given.children
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
//#endregion
|
|
197
222
|
//#region src/components/button-link.tsx
|
|
198
223
|
function ButtonLink({ className, variant, size, render, disabled, children, ...props }) {
|
|
199
224
|
const classes = cn(buttonVariants({
|
|
200
225
|
variant,
|
|
201
226
|
size
|
|
202
227
|
}), disabled && "pointer-events-none opacity-50", className);
|
|
203
|
-
|
|
228
|
+
return renderWith(render, {
|
|
204
229
|
...props,
|
|
205
230
|
"data-slot": "button-link",
|
|
206
231
|
className: classes,
|
|
207
232
|
"aria-disabled": disabled || void 0,
|
|
208
233
|
tabIndex: disabled ? -1 : props.tabIndex
|
|
209
|
-
};
|
|
210
|
-
if (render) {
|
|
211
|
-
const Element = render.type;
|
|
212
|
-
return /* @__PURE__ */ jsx(Element, {
|
|
213
|
-
...render.props,
|
|
214
|
-
...merged,
|
|
215
|
-
children: children ?? render.props.children
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
return /* @__PURE__ */ jsx("a", {
|
|
219
|
-
...merged,
|
|
220
|
-
children
|
|
221
|
-
});
|
|
234
|
+
}, children, "a");
|
|
222
235
|
}
|
|
223
236
|
//#endregion
|
|
224
237
|
//#region src/components/card.tsx
|
|
225
|
-
|
|
226
|
-
|
|
238
|
+
/**
|
|
239
|
+
* Card — the bordered surface everything else sits on. `render` changes the
|
|
240
|
+
* element without changing the look, which is how a card becomes a landmark.
|
|
241
|
+
*/
|
|
242
|
+
function Card({ className, hover, accent, render, children, ...props }) {
|
|
243
|
+
return renderWith(render, {
|
|
227
244
|
"data-slot": "card",
|
|
228
245
|
"data-accent": accent ? "" : void 0,
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
});
|
|
246
|
+
...props,
|
|
247
|
+
className: cn("flex flex-col rounded-[var(--ds-radius-lg)] border bg-[var(--ds-card)] text-[color:var(--ds-foreground)]", "transition-[border-color,background-color] duration-[var(--ds-duration-fast)] ease-[var(--ds-ease-out)]", accent ? "border-[var(--ds-ring)]" : "border-[var(--ds-border-subtle)]", hover && "hover:border-[var(--ds-border)] hover:bg-[var(--ds-popover)]", className)
|
|
248
|
+
}, children, "div");
|
|
232
249
|
}
|
|
233
250
|
function CardHeader({ className, ...props }) {
|
|
234
251
|
return /* @__PURE__ */ jsx("div", {
|
|
@@ -484,6 +501,9 @@ function seriesColor(config, key, index) {
|
|
|
484
501
|
const position = (config ? Object.keys(config) : []).indexOf(key);
|
|
485
502
|
return vizVar(position >= 0 ? position : index ?? 0);
|
|
486
503
|
}
|
|
504
|
+
/** The box `testMode` falls back to when the layout gives the chart none. */
|
|
505
|
+
const TEST_WIDTH = 600;
|
|
506
|
+
const TEST_HEIGHT = 300;
|
|
487
507
|
/**
|
|
488
508
|
* ChartContainer — the sized, token-styled surface every chart draws in.
|
|
489
509
|
*
|
|
@@ -492,7 +512,7 @@ function seriesColor(config, key, index) {
|
|
|
492
512
|
* cursor classes from tokens with a caption-sm floor for text, so a custom
|
|
493
513
|
* chart composed inside it needs no local colours or fonts.
|
|
494
514
|
*/
|
|
495
|
-
function ChartContainer({ config = {}, height = 300, responsive = true, className, style, children, ...props }) {
|
|
515
|
+
function ChartContainer({ config = {}, height = 300, responsive = true, testMode = false, className, style, children, ...props }) {
|
|
496
516
|
const [element, setElement] = React.useState(null);
|
|
497
517
|
const vars = React.useMemo(() => {
|
|
498
518
|
const out = {};
|
|
@@ -508,9 +528,14 @@ function ChartContainer({ config = {}, height = 300, responsive = true, classNam
|
|
|
508
528
|
children: /* @__PURE__ */ jsx("div", {
|
|
509
529
|
ref: setElement,
|
|
510
530
|
"data-slot": "chart",
|
|
531
|
+
"data-test-mode": testMode ? "" : void 0,
|
|
511
532
|
className: cn("relative w-full min-w-0 overflow-hidden text-[length:var(--ds-text-caption-sm)] text-[color:var(--ds-foreground)]", responsive ? "flex justify-center" : "block [&>div]:h-full [&>div]:w-full", "[&_.recharts-cartesian-axis-tick-value]:fill-[var(--ds-muted-foreground)]", "[&_.recharts-polar-angle-axis-tick-value]:fill-[var(--ds-muted-foreground)]", "[&_.recharts-polar-radius-axis-tick-value]:fill-[var(--ds-muted-foreground)]", "[&_.recharts-cartesian-grid-horizontal_line]:stroke-[var(--ds-border-subtle)]", "[&_.recharts-cartesian-grid-vertical_line]:stroke-[var(--ds-border-subtle)]", "[&_.recharts-polar-grid-angle_line]:stroke-[var(--ds-border-subtle)]", "[&_.recharts-polar-grid-concentric-polygon]:stroke-[var(--ds-border-subtle)]", "[&_.recharts-polar-grid-concentric-circle]:stroke-[var(--ds-border-subtle)]", "[&_.recharts-cartesian-axis-line]:stroke-[var(--ds-border)]", "[&_.recharts-cartesian-axis-tick-line]:stroke-[var(--ds-border)]", "[&_.recharts-radial-bar-background-sector]:fill-[var(--ds-muted)]", "[&_.recharts-rectangle.recharts-tooltip-cursor]:fill-[var(--ds-hover)]", "[&_.recharts-curve.recharts-tooltip-cursor]:stroke-[var(--ds-border-strong)]", "[&_.recharts-reference-line_line]:stroke-[var(--ds-border-strong)]", "[&_.recharts-pie-sector_.recharts-sector]:stroke-[var(--ds-card)]", "[&_.recharts-funnel-trapezoid_.recharts-trapezoid]:stroke-[var(--ds-card)]", "[&_.recharts-layer]:outline-hidden [&_.recharts-surface]:outline-hidden [&_.recharts-sector]:outline-hidden", "[&_text]:font-[family-name:var(--ds-font-body)]", className),
|
|
512
533
|
style: {
|
|
513
534
|
height,
|
|
535
|
+
...testMode ? {
|
|
536
|
+
minWidth: TEST_WIDTH,
|
|
537
|
+
minHeight: TEST_HEIGHT
|
|
538
|
+
} : null,
|
|
514
539
|
...vars,
|
|
515
540
|
...style
|
|
516
541
|
},
|
|
@@ -518,6 +543,8 @@ function ChartContainer({ config = {}, height = 300, responsive = true, classNam
|
|
|
518
543
|
children: responsive ? /* @__PURE__ */ jsx(ResponsiveContainer$1, {
|
|
519
544
|
width: "100%",
|
|
520
545
|
height: "100%",
|
|
546
|
+
minWidth: testMode ? TEST_WIDTH : void 0,
|
|
547
|
+
minHeight: testMode ? TEST_HEIGHT : void 0,
|
|
521
548
|
children
|
|
522
549
|
}) : children
|
|
523
550
|
})
|
|
@@ -650,6 +677,30 @@ function ChartLegend(props) {
|
|
|
650
677
|
function isSeriesArray(data) {
|
|
651
678
|
return Array.isArray(data) && data.length > 0 && data.every((d) => d && typeof d === "object" && Array.isArray(d.data));
|
|
652
679
|
}
|
|
680
|
+
/** True for the `{ rows, columns, values }` categorical matrix shape. */
|
|
681
|
+
function isMatrix(data) {
|
|
682
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) return false;
|
|
683
|
+
const m = data;
|
|
684
|
+
return Array.isArray(m.rows) && Array.isArray(m.columns) && Array.isArray(m.values);
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Pivot a categorical matrix onto the Nivo heatmap shape. Every row gets a
|
|
688
|
+
* point for every column so the grid stays rectangular; a missing or
|
|
689
|
+
* non-finite cell becomes `null`, which Nivo paints with `emptyColor` rather
|
|
690
|
+
* than as a zero.
|
|
691
|
+
*/
|
|
692
|
+
function matrixToSeries(matrix) {
|
|
693
|
+
return matrix.rows.map((row, r) => ({
|
|
694
|
+
id: row,
|
|
695
|
+
data: matrix.columns.map((column, c) => {
|
|
696
|
+
const value = matrix.values[r]?.[c];
|
|
697
|
+
return {
|
|
698
|
+
x: column,
|
|
699
|
+
y: typeof value === "number" && Number.isFinite(value) ? value : null
|
|
700
|
+
};
|
|
701
|
+
})
|
|
702
|
+
}));
|
|
703
|
+
}
|
|
653
704
|
/**
|
|
654
705
|
* Infer the category key and the series keys of a row array the way the
|
|
655
706
|
* webchat renderer did: the first string field is the index, every numeric
|
|
@@ -732,6 +783,7 @@ function treeIdentity(tree) {
|
|
|
732
783
|
/** True when there is nothing to draw. */
|
|
733
784
|
function isEmptyData(data) {
|
|
734
785
|
if (data == null) return true;
|
|
786
|
+
if (isMatrix(data)) return data.rows.length === 0 || data.columns.length === 0;
|
|
735
787
|
if (Array.isArray(data)) {
|
|
736
788
|
if (data.length === 0) return true;
|
|
737
789
|
if (isSeriesArray(data)) return data.every((s) => s.data.length === 0);
|
|
@@ -898,14 +950,28 @@ function useNivoTheme() {
|
|
|
898
950
|
}
|
|
899
951
|
//#endregion
|
|
900
952
|
//#region src/components/chart/nivo-charts.tsx
|
|
901
|
-
const
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
953
|
+
const loaders = {
|
|
954
|
+
"heatmap-svg": async () => (await import("@nivo/heatmap")).ResponsiveHeatMap,
|
|
955
|
+
"heatmap-canvas": async () => (await import("@nivo/heatmap")).ResponsiveHeatMapCanvas,
|
|
956
|
+
"calendar-svg": async () => (await import("@nivo/calendar")).ResponsiveCalendar,
|
|
957
|
+
"calendar-canvas": async () => (await import("@nivo/calendar")).ResponsiveCalendarCanvas,
|
|
958
|
+
"treemap-svg": async () => (await import("@nivo/treemap")).ResponsiveTreeMap,
|
|
959
|
+
"treemap-canvas": async () => (await import("@nivo/treemap")).ResponsiveTreeMapCanvas,
|
|
960
|
+
"sunburst-svg": async () => (await import("@nivo/sunburst")).ResponsiveSunburst
|
|
961
|
+
};
|
|
962
|
+
let chunks = /* @__PURE__ */ new Map();
|
|
963
|
+
function chunk(name) {
|
|
964
|
+
let component = chunks.get(name);
|
|
965
|
+
if (!component) {
|
|
966
|
+
component = React.lazy(async () => ({ default: await loaders[name]() }));
|
|
967
|
+
chunks.set(name, component);
|
|
968
|
+
}
|
|
969
|
+
return component;
|
|
970
|
+
}
|
|
971
|
+
/** Forget every loaded-or-failed Nivo chunk, so the next render loads it again. */
|
|
972
|
+
function resetNivoChunks() {
|
|
973
|
+
chunks = /* @__PURE__ */ new Map();
|
|
974
|
+
}
|
|
909
975
|
/**
|
|
910
976
|
* Resolved series colours for Nivo: config colours are `var()` strings, which
|
|
911
977
|
* Nivo cannot use, so a configured colour is resolved through the container's
|
|
@@ -955,8 +1021,8 @@ function NivoChart({ type, data, config, renderer, scale, legend, valueFormatter
|
|
|
955
1021
|
const labelOn = (d) => onFill(d.color);
|
|
956
1022
|
switch (type) {
|
|
957
1023
|
case "heatmap": {
|
|
958
|
-
const Component = canvas ?
|
|
959
|
-
const rows = data;
|
|
1024
|
+
const Component = chunk(canvas ? "heatmap-canvas" : "heatmap-svg");
|
|
1025
|
+
const rows = isMatrix(data) ? matrixToSeries(data) : data;
|
|
960
1026
|
const cells = rows.reduce((n, r) => n + r.data.length, 0);
|
|
961
1027
|
const colorConfig = scale === "diverging" ? {
|
|
962
1028
|
type: "diverging",
|
|
@@ -1004,7 +1070,7 @@ function NivoChart({ type, data, config, renderer, scale, legend, valueFormatter
|
|
|
1004
1070
|
});
|
|
1005
1071
|
}
|
|
1006
1072
|
case "calendar": {
|
|
1007
|
-
const Component = canvas ?
|
|
1073
|
+
const Component = chunk(canvas ? "calendar-canvas" : "calendar-svg");
|
|
1008
1074
|
const days = data;
|
|
1009
1075
|
const range = calendarRange(days, from, to);
|
|
1010
1076
|
return /* @__PURE__ */ jsx(Component, {
|
|
@@ -1038,7 +1104,7 @@ function NivoChart({ type, data, config, renderer, scale, legend, valueFormatter
|
|
|
1038
1104
|
});
|
|
1039
1105
|
}
|
|
1040
1106
|
case "treemap": {
|
|
1041
|
-
const Component = canvas ?
|
|
1107
|
+
const Component = chunk(canvas ? "treemap-canvas" : "treemap-svg");
|
|
1042
1108
|
const tree = data;
|
|
1043
1109
|
return /* @__PURE__ */ jsx(Component, {
|
|
1044
1110
|
data: tree,
|
|
@@ -1065,8 +1131,9 @@ function NivoChart({ type, data, config, renderer, scale, legend, valueFormatter
|
|
|
1065
1131
|
});
|
|
1066
1132
|
}
|
|
1067
1133
|
case "sunburst": {
|
|
1134
|
+
const Component = chunk("sunburst-svg");
|
|
1068
1135
|
const tree = data;
|
|
1069
|
-
return /* @__PURE__ */ jsx(
|
|
1136
|
+
return /* @__PURE__ */ jsx(Component, {
|
|
1070
1137
|
data: tree,
|
|
1071
1138
|
id: treeIdentity(tree),
|
|
1072
1139
|
value: "value",
|
|
@@ -1342,21 +1409,43 @@ function seriesKeys(type, data, indexBy, keys) {
|
|
|
1342
1409
|
case "pie":
|
|
1343
1410
|
case "donut":
|
|
1344
1411
|
case "funnel": return toSlices(data).map((s) => s.id);
|
|
1412
|
+
case "heatmap":
|
|
1413
|
+
if (isMatrix(data)) return data.rows.map(String);
|
|
1414
|
+
return isSeriesArray(data) ? data.map((s) => String(s.id)) : [];
|
|
1345
1415
|
case "scatter":
|
|
1346
|
-
case "scatterplot":
|
|
1347
|
-
case "heatmap": return isSeriesArray(data) ? data.map((s) => String(s.id)) : [];
|
|
1416
|
+
case "scatterplot": return isSeriesArray(data) ? data.map((s) => String(s.id)) : [];
|
|
1348
1417
|
case "treemap":
|
|
1349
1418
|
case "sunburst": return (data.children ?? []).map((c) => String(c.id ?? c.name ?? ""));
|
|
1350
1419
|
case "calendar": return [];
|
|
1351
1420
|
}
|
|
1352
1421
|
}
|
|
1422
|
+
/**
|
|
1423
|
+
* Catches a Nivo chunk that failed to load. Recovering takes two things,
|
|
1424
|
+
* because `React.lazy` memoises a rejection for the life of the page: fresh
|
|
1425
|
+
* lazy components ({@link resetNivoChunks}) and a boundary that leaves its
|
|
1426
|
+
* failed state. `resetKey` does the second on its own when the chart changes,
|
|
1427
|
+
* and the fallback gets a `retry` that does both.
|
|
1428
|
+
*/
|
|
1353
1429
|
var ChunkBoundary = class extends React.Component {
|
|
1354
|
-
state = {
|
|
1430
|
+
state = {
|
|
1431
|
+
failed: false,
|
|
1432
|
+
key: this.props.resetKey
|
|
1433
|
+
};
|
|
1355
1434
|
static getDerivedStateFromError() {
|
|
1356
1435
|
return { failed: true };
|
|
1357
1436
|
}
|
|
1437
|
+
static getDerivedStateFromProps(props, state) {
|
|
1438
|
+
return props.resetKey === state.key ? null : {
|
|
1439
|
+
failed: false,
|
|
1440
|
+
key: props.resetKey
|
|
1441
|
+
};
|
|
1442
|
+
}
|
|
1443
|
+
retry = () => {
|
|
1444
|
+
resetNivoChunks();
|
|
1445
|
+
this.setState({ failed: false });
|
|
1446
|
+
};
|
|
1358
1447
|
render() {
|
|
1359
|
-
return this.state.failed ? this.props.fallback : this.props.children;
|
|
1448
|
+
return this.state.failed ? this.props.fallback(this.retry) : this.props.children;
|
|
1360
1449
|
}
|
|
1361
1450
|
};
|
|
1362
1451
|
/**
|
|
@@ -1368,6 +1457,14 @@ var ChunkBoundary = class extends React.Component {
|
|
|
1368
1457
|
* Colours, fonts, axes, grid, tooltip, legend and the empty, loading and
|
|
1369
1458
|
* error states all come from cortena-design tokens; a consumer passes data
|
|
1370
1459
|
* and, optionally, a `config` of labels.
|
|
1460
|
+
*
|
|
1461
|
+
* `heatmap` takes either the Nivo series shape or a categorical
|
|
1462
|
+
* {@link ChartMatrix} — `{ rows, columns, values }` — for the correlation and
|
|
1463
|
+
* confusion matrices that are already in that form.
|
|
1464
|
+
*
|
|
1465
|
+
* `testMode` gives the drawing area a 600×300 floor so a chart still draws
|
|
1466
|
+
* where the layout gives it no size; see {@link ChartContainerProps.testMode}
|
|
1467
|
+
* and README.md, "Charts in tests".
|
|
1371
1468
|
*/
|
|
1372
1469
|
function Chart({ type, data, config, renderer = "svg", indexBy, keys, stacked, scale = "sequential", legend, grid = true, tooltip = true, valueFormatter, from, to, loading, error, emptyMessage, className, height, ...props }) {
|
|
1373
1470
|
const engine = chartEngine(type);
|
|
@@ -1388,7 +1485,18 @@ function Chart({ type, data, config, renderer = "svg", indexBy, keys, stacked, s
|
|
|
1388
1485
|
else if (errorText) body = /* @__PURE__ */ jsx(ChartError, { children: errorText });
|
|
1389
1486
|
else if (empty) body = /* @__PURE__ */ jsx(ChartEmpty, { children: emptyMessage });
|
|
1390
1487
|
else if (engine === "nivo") body = /* @__PURE__ */ jsx(ChunkBoundary, {
|
|
1391
|
-
|
|
1488
|
+
resetKey: `${type}|${renderer}`,
|
|
1489
|
+
fallback: (retry) => /* @__PURE__ */ jsxs(ChartError, { children: [
|
|
1490
|
+
"Chart could not be loaded.",
|
|
1491
|
+
" ",
|
|
1492
|
+
/* @__PURE__ */ jsx("button", {
|
|
1493
|
+
type: "button",
|
|
1494
|
+
"data-slot": "chart-retry",
|
|
1495
|
+
onClick: retry,
|
|
1496
|
+
className: "underline underline-offset-2",
|
|
1497
|
+
children: "Retry"
|
|
1498
|
+
})
|
|
1499
|
+
] }),
|
|
1392
1500
|
children: /* @__PURE__ */ jsx(React.Suspense, {
|
|
1393
1501
|
fallback: /* @__PURE__ */ jsx(ChartLoading, {}),
|
|
1394
1502
|
children: /* @__PURE__ */ jsx(NivoChart, {
|
|
@@ -1512,15 +1620,22 @@ function Input({ className, type, ...props }) {
|
|
|
1512
1620
|
//#endregion
|
|
1513
1621
|
//#region src/components/spinner.tsx
|
|
1514
1622
|
/**
|
|
1515
|
-
* Spinner — a ring with a
|
|
1623
|
+
* Spinner — a ring with a coloured leading edge. Announces itself as
|
|
1516
1624
|
* `role="status"` with a "Loading" label; pass `aria-label` to override.
|
|
1625
|
+
*
|
|
1626
|
+
* ```tsx
|
|
1627
|
+
* <Button disabled>
|
|
1628
|
+
* <Spinner tone="inverse" /> Saving…
|
|
1629
|
+
* </Button>
|
|
1630
|
+
* ```
|
|
1517
1631
|
*/
|
|
1518
|
-
function Spinner({ className, size = 16, style, ...props }) {
|
|
1632
|
+
function Spinner({ className, size = 16, tone = "default", style, ...props }) {
|
|
1519
1633
|
return /* @__PURE__ */ jsx("span", {
|
|
1520
1634
|
"data-slot": "spinner",
|
|
1635
|
+
"data-tone": tone,
|
|
1521
1636
|
role: "status",
|
|
1522
1637
|
"aria-label": "Loading",
|
|
1523
|
-
className: cn("inline-block shrink-0 animate-spin rounded-[var(--ds-radius-full)]", "border-
|
|
1638
|
+
className: cn("inline-block shrink-0 animate-spin rounded-[var(--ds-radius-full)] border-2", tone === "inverse" ? "border-[var(--ds-primary-foreground)]/35 border-t-[var(--ds-primary-foreground)]" : "border-[var(--ds-border)] border-t-[var(--ds-primary)]", className),
|
|
1524
1639
|
style: {
|
|
1525
1640
|
width: size,
|
|
1526
1641
|
height: size,
|
|
@@ -1713,21 +1828,6 @@ function DropdownMenuShortcut({ className, ...props }) {
|
|
|
1713
1828
|
}
|
|
1714
1829
|
//#endregion
|
|
1715
1830
|
//#region src/components/select.tsx
|
|
1716
|
-
/**
|
|
1717
|
-
* Select.
|
|
1718
|
-
*
|
|
1719
|
-
* `SelectContent` composes Base UI's Portal + Positioner + Popup so consumers
|
|
1720
|
-
* keep writing `<SelectContent side="bottom" align="start">`; positioning
|
|
1721
|
-
* props are forwarded to the Positioner, which is where Base UI reads them.
|
|
1722
|
-
*
|
|
1723
|
-
* Radix users:
|
|
1724
|
-
* - `SelectValue` shows the raw value unless the Root is given `items`
|
|
1725
|
-
* (`{ [value]: label }` or `[{ value, label }]`) or `itemToStringLabel`;
|
|
1726
|
-
* Base UI does not read the label out of an unmounted `SelectItem`.
|
|
1727
|
-
* - `onValueChange` receives `(value, eventDetails)`.
|
|
1728
|
-
* - `SelectContent` defaults to the dropdown layout; pass
|
|
1729
|
-
* `alignItemWithTrigger` for Base UI's native-like overlay of the selected item.
|
|
1730
|
-
*/
|
|
1731
1831
|
function Select(props) {
|
|
1732
1832
|
return /* @__PURE__ */ jsx(Select$1.Root, { ...props });
|
|
1733
1833
|
}
|
|
@@ -1850,12 +1950,25 @@ function toSheet(table, rows = exportRows(table)) {
|
|
|
1850
1950
|
}))
|
|
1851
1951
|
};
|
|
1852
1952
|
}
|
|
1953
|
+
/**
|
|
1954
|
+
* Text a spreadsheet would evaluate rather than display. Excel, Sheets and
|
|
1955
|
+
* LibreOffice all treat a leading `=`, `+`, `-` or `@` as the start of a
|
|
1956
|
+
* formula, and a leading tab or CR as whitespace they strip before looking
|
|
1957
|
+
* again — so `\t=cmd|'/c calc'!A1` is a formula too. Only strings are checked:
|
|
1958
|
+
* a number, boolean or Date cell cannot carry one, and prefixing `-5` would
|
|
1959
|
+
* turn a number column into text.
|
|
1960
|
+
*/
|
|
1961
|
+
const FORMULA_START = /^[=+\-@\t\r]/;
|
|
1853
1962
|
function csvField(value) {
|
|
1854
1963
|
if (value == null) return "";
|
|
1855
|
-
|
|
1964
|
+
let text = value instanceof Date ? value.toISOString() : String(value);
|
|
1965
|
+
if (typeof value === "string" && FORMULA_START.test(text)) text = `'${text}`;
|
|
1856
1966
|
return /[",\n\r]/.test(text) ? `"${text.replace(/"/g, "\"\"")}"` : text;
|
|
1857
1967
|
}
|
|
1858
|
-
/**
|
|
1968
|
+
/**
|
|
1969
|
+
* RFC 4180 text: comma separated, CRLF lines, quotes doubled. A cell that a
|
|
1970
|
+
* spreadsheet would read as a formula is prefixed with `'` so it stays text.
|
|
1971
|
+
*/
|
|
1859
1972
|
function toCsv(table, rows) {
|
|
1860
1973
|
const { headers, records } = toSheet(table, rows);
|
|
1861
1974
|
return [headers, ...records].map((line) => line.map(csvField).join(",")).join("\r\n");
|
|
@@ -2542,14 +2655,20 @@ function useLocalStrategy(source, query, mode) {
|
|
|
2542
2655
|
const targetPage = infinite ? loadedForScope.length : query.page;
|
|
2543
2656
|
const needs = infinite ? loadedForScope.length < wantedPages : !(state.scopeKey === scopeKey && state.page === query.page && state.pages.length > 0);
|
|
2544
2657
|
const requestKey = `${scopeKey}|${targetPage}|${tick}`;
|
|
2658
|
+
const fetchRef = React.useRef(fetch);
|
|
2659
|
+
React.useEffect(() => {
|
|
2660
|
+
fetchRef.current = fetch;
|
|
2661
|
+
});
|
|
2662
|
+
const hasFetch = Boolean(fetch);
|
|
2545
2663
|
React.useEffect(() => {
|
|
2546
|
-
|
|
2664
|
+
const run = fetchRef.current;
|
|
2665
|
+
if (!run || !needs) return;
|
|
2547
2666
|
const controller = new AbortController();
|
|
2548
2667
|
setState((s) => ({
|
|
2549
2668
|
...s,
|
|
2550
2669
|
isFetching: true
|
|
2551
2670
|
}));
|
|
2552
|
-
|
|
2671
|
+
run({
|
|
2553
2672
|
...scope,
|
|
2554
2673
|
page: targetPage
|
|
2555
2674
|
}, controller.signal).then((result) => {
|
|
@@ -2571,7 +2690,7 @@ function useLocalStrategy(source, query, mode) {
|
|
|
2571
2690
|
});
|
|
2572
2691
|
return () => controller.abort();
|
|
2573
2692
|
}, [
|
|
2574
|
-
|
|
2693
|
+
hasFetch,
|
|
2575
2694
|
requestKey,
|
|
2576
2695
|
needs
|
|
2577
2696
|
]);
|
|
@@ -2808,7 +2927,7 @@ function DataTable(props) {
|
|
|
2808
2927
|
return /* @__PURE__ */ jsx(DataTableOwned, { ...props });
|
|
2809
2928
|
}
|
|
2810
2929
|
function DataTableOwned(props) {
|
|
2811
|
-
const { className, maxHeight, virtualize, rowHeight, stickyHeader, density, renderSubComponent, toolbar, bulkActions, toolbarActions, searchPlaceholder, emptyState, emptyMessage, pageSizeOptions, enableExport, exportFileName, loading, error, onRowClick, ...options } = props;
|
|
2930
|
+
const { className, maxHeight, virtualize, rowHeight, stickyHeader, density, renderSubComponent, toolbar, bulkActions, toolbarActions, searchPlaceholder, emptyState, emptyMessage, pageSizeOptions, enableExport, exportFileName, loading, error, onRowClick, activeRowId, rowClassName, ...options } = props;
|
|
2812
2931
|
const instance = useDataTable({
|
|
2813
2932
|
...options,
|
|
2814
2933
|
enableExpanding: options.enableExpanding ?? Boolean(renderSubComponent)
|
|
@@ -2833,7 +2952,9 @@ function DataTableOwned(props) {
|
|
|
2833
2952
|
exportFileName,
|
|
2834
2953
|
loading,
|
|
2835
2954
|
error,
|
|
2836
|
-
onRowClick
|
|
2955
|
+
onRowClick,
|
|
2956
|
+
activeRowId,
|
|
2957
|
+
rowClassName
|
|
2837
2958
|
});
|
|
2838
2959
|
}
|
|
2839
2960
|
function pinAttrs(column, table) {
|
|
@@ -2911,7 +3032,7 @@ function EditableCell({ cell, instance, onDone }) {
|
|
|
2911
3032
|
className: "h-7 px-2 py-0 text-[length:var(--ds-text-body-sm)]"
|
|
2912
3033
|
});
|
|
2913
3034
|
}
|
|
2914
|
-
function DataTableView({ instance, className, maxHeight, virtualize, rowHeight = 40, stickyHeader = true, density = "default", renderSubComponent, toolbar = true, bulkActions, toolbarActions, searchPlaceholder, emptyState, emptyMessage = "No results", pageSizeOptions, enableExport = true, exportFileName = "export", loading, error, onRowClick }) {
|
|
3035
|
+
function DataTableView({ instance, className, maxHeight, virtualize, rowHeight = 40, stickyHeader = true, density = "default", renderSubComponent, toolbar = true, bulkActions, toolbarActions, searchPlaceholder, emptyState, emptyMessage = "No results", pageSizeOptions, enableExport = true, exportFileName = "export", loading, error, onRowClick, activeRowId, rowClassName }) {
|
|
2915
3036
|
const { table, paginationMode } = instance;
|
|
2916
3037
|
const rows = table.getRowModel().rows;
|
|
2917
3038
|
const leafColumns = table.getVisibleLeafColumns();
|
|
@@ -3101,6 +3222,7 @@ function DataTableView({ instance, className, maxHeight, virtualize, rowHeight =
|
|
|
3101
3222
|
const endStart = cells.findIndex((cell) => cell.column.getIsPinned() === "end");
|
|
3102
3223
|
const splitAt = endStart === -1 ? cells.length : endStart;
|
|
3103
3224
|
const selected = row.getIsSelected();
|
|
3225
|
+
const active = activeRowId != null && row.id === activeRowId;
|
|
3104
3226
|
const expanded = renderSubComponent && row.getIsExpanded();
|
|
3105
3227
|
const renderCell = (cell, c) => {
|
|
3106
3228
|
const column = cell.column;
|
|
@@ -3127,7 +3249,7 @@ function DataTableView({ instance, className, maxHeight, virtualize, rowHeight =
|
|
|
3127
3249
|
rowId: row.id,
|
|
3128
3250
|
columnId: column.id
|
|
3129
3251
|
}) : void 0,
|
|
3130
|
-
className: cn("relative align-middle outline-none", isEditing ? "px-1.5 py-1" : cellPadding, alignClass[meta?.align ?? "start"], "focus-visible:ring-[2px] focus-visible:ring-inset focus-visible:ring-[var(--ds-ring)]", pin.pinned && "z-[1] bg-[var(--ds-card)] group-hover/row:bg-[linear-gradient(var(--ds-hover),var(--ds-hover))] group-data-[selected]/row:bg-[linear-gradient(var(--ds-primary-soft),var(--ds-primary-soft))]", pin.pinned === "start" && pin.edge && "shadow-[inset_-1px_0_0_var(--ds-border)]", pin.pinned === "end" && pin.edge && "shadow-[inset_1px_0_0_var(--ds-border)]", !isEditing && "truncate", meta?.cellClassName),
|
|
3252
|
+
className: cn("relative align-middle outline-none", isEditing ? "px-1.5 py-1" : cellPadding, alignClass[meta?.align ?? "start"], "focus-visible:ring-[2px] focus-visible:ring-inset focus-visible:ring-[var(--ds-ring)]", pin.pinned && "z-[1] bg-[var(--ds-card)] group-hover/row:bg-[linear-gradient(var(--ds-hover),var(--ds-hover))] group-data-[selected]/row:bg-[linear-gradient(var(--ds-primary-soft),var(--ds-primary-soft))] group-data-[active]/row:bg-[linear-gradient(var(--ds-primary-soft),var(--ds-primary-soft))]", pin.pinned === "start" && pin.edge && "shadow-[inset_-1px_0_0_var(--ds-border)]", pin.pinned === "end" && pin.edge && "shadow-[inset_1px_0_0_var(--ds-border)]", !isEditing && "truncate", meta?.cellClassName),
|
|
3131
3253
|
children: isEditing ? /* @__PURE__ */ jsx(EditableCell, {
|
|
3132
3254
|
cell,
|
|
3133
3255
|
instance,
|
|
@@ -3145,12 +3267,13 @@ function DataTableView({ instance, className, maxHeight, virtualize, rowHeight =
|
|
|
3145
3267
|
"data-slot": "data-table-row",
|
|
3146
3268
|
"data-index": virtualIndex,
|
|
3147
3269
|
"data-selected": selected ? "" : void 0,
|
|
3270
|
+
"data-active": active ? "" : void 0,
|
|
3148
3271
|
"data-expanded": expanded ? "" : void 0,
|
|
3149
3272
|
"aria-rowindex": index + 2,
|
|
3150
3273
|
"aria-selected": table.options.enableRowSelection ? selected : void 0,
|
|
3151
3274
|
ref: isVirtual ? virtualizer.measureElement : void 0,
|
|
3152
3275
|
onClick: onRowClick ? (e) => onRowClick(row.original, e) : void 0,
|
|
3153
|
-
className: cn("group/row border-b border-[var(--ds-border-subtle)] transition-colors duration-[var(--ds-duration-fast)]", "hover:bg-[var(--ds-hover)] data-[selected]:bg-[var(--ds-primary-soft)]", onRowClick && "cursor-pointer"),
|
|
3276
|
+
className: cn("group/row border-b border-[var(--ds-border-subtle)] transition-colors duration-[var(--ds-duration-fast)]", "hover:bg-[var(--ds-hover)] data-[selected]:bg-[var(--ds-primary-soft)]", "data-[active]:bg-[var(--ds-primary-soft)]", onRowClick && "cursor-pointer", rowClassName?.(row.original)),
|
|
3154
3277
|
children: [
|
|
3155
3278
|
cells.slice(0, splitAt).map((cell, c) => renderCell(cell, c)),
|
|
3156
3279
|
/* @__PURE__ */ jsx("td", {
|
|
@@ -4205,6 +4328,10 @@ function RadioGroupItem({ className, ...props }) {
|
|
|
4205
4328
|
* SectionCard — a Card with a header row (title, description, actions), a
|
|
4206
4329
|
* body and an optional footer. It composes the Card parts rather than
|
|
4207
4330
|
* restyling them, so a SectionCard and a hand-built Card look identical.
|
|
4331
|
+
*
|
|
4332
|
+
* `render` is Card's and reaches the outer element, so a section card can be
|
|
4333
|
+
* the landmark it is named after: `render={<section aria-labelledby={id} />}`
|
|
4334
|
+
* with the same `id` on the title, or `render={<aside />}` for a side panel.
|
|
4208
4335
|
*/
|
|
4209
4336
|
function SectionCard({ title, description, actions, footer, flush, bodyClassName, children, ...props }) {
|
|
4210
4337
|
return /* @__PURE__ */ jsxs(Card, {
|
|
@@ -4263,6 +4390,7 @@ const TONE_CLASS = {
|
|
|
4263
4390
|
accent: "bg-[var(--ds-primary)]",
|
|
4264
4391
|
success: "bg-[var(--ds-success)]",
|
|
4265
4392
|
warning: "bg-[var(--ds-warning)]",
|
|
4393
|
+
destructive: "bg-[var(--ds-destructive)]",
|
|
4266
4394
|
danger: "bg-[var(--ds-destructive)]",
|
|
4267
4395
|
info: "bg-[var(--ds-info)]",
|
|
4268
4396
|
neutral: "bg-[var(--ds-text-tertiary)]"
|
|
@@ -5064,14 +5192,21 @@ const buttonSize = z.enum([
|
|
|
5064
5192
|
"lg"
|
|
5065
5193
|
]).describe("Control size.");
|
|
5066
5194
|
/**
|
|
5195
|
+
* Root-relative means one slash and then a path. `//evil.example/x` is
|
|
5196
|
+
* protocol-relative — the browser resolves it against the page's scheme and
|
|
5197
|
+
* goes off-origin — and `/\evil.example` is the same trick, because browsers
|
|
5198
|
+
* treat a backslash after the leading slash as a second slash.
|
|
5199
|
+
*/
|
|
5200
|
+
const rootRelative = (value) => value.startsWith("/") && value[1] !== "/" && value[1] !== "\\";
|
|
5201
|
+
/**
|
|
5067
5202
|
* A URL an agent may point at.
|
|
5068
5203
|
*
|
|
5069
5204
|
* Restricted by scheme rather than sanitised after the fact: `javascript:` and
|
|
5070
5205
|
* friends never reach the DOM because they never pass validation, so the
|
|
5071
5206
|
* component gets an error card instead.
|
|
5072
5207
|
*/
|
|
5073
|
-
const httpUrl = z.string().refine((value) => /^https?:\/\//i.test(value) || value
|
|
5074
|
-
const imageUrl = z.string().refine((value) => /^https?:\/\//i.test(value) || /^data:image\//i.test(value) || value
|
|
5208
|
+
const httpUrl = z.string().refine((value) => /^https?:\/\//i.test(value) || rootRelative(value) || value.startsWith("#"), "Must be an http(s), root-relative or fragment URL.").describe("Destination URL (http, https, root-relative or fragment).");
|
|
5209
|
+
const imageUrl = z.string().refine((value) => /^https?:\/\//i.test(value) || /^data:image\//i.test(value) || rootRelative(value), "Must be an http(s), root-relative or data:image URL.").describe("Image URL (http, https, root-relative or data:image).");
|
|
5075
5210
|
/** Every chart type the Chart composite draws, Recharts and Nivo alike. */
|
|
5076
5211
|
const chartType = z.enum([
|
|
5077
5212
|
"bar",
|
|
@@ -6744,6 +6879,119 @@ function AvatarFallback({ className, ...props }) {
|
|
|
6744
6879
|
});
|
|
6745
6880
|
}
|
|
6746
6881
|
//#endregion
|
|
6882
|
+
//#region src/components/breadcrumb.tsx
|
|
6883
|
+
/**
|
|
6884
|
+
* Breadcrumb — the trail above a page title.
|
|
6885
|
+
*
|
|
6886
|
+
* A `<nav aria-label="Breadcrumb">` around an ordered list, which is what
|
|
6887
|
+
* assistive technology expects: the list order is the hierarchy, so a screen
|
|
6888
|
+
* reader announces "list, 4 items" and reads the path in order. Separators are
|
|
6889
|
+
* decorative list items, not text inside the links, so a link's accessible
|
|
6890
|
+
* name is the crumb and nothing else.
|
|
6891
|
+
*
|
|
6892
|
+
* The last crumb is `BreadcrumbPage`, not a link: it is the page you are on,
|
|
6893
|
+
* so it carries `aria-current="page"` and is not focusable. Everything before
|
|
6894
|
+
* it is a `BreadcrumbLink`.
|
|
6895
|
+
*
|
|
6896
|
+
* ```tsx
|
|
6897
|
+
* <Breadcrumb>
|
|
6898
|
+
* <BreadcrumbList>
|
|
6899
|
+
* <BreadcrumbItem>
|
|
6900
|
+
* <BreadcrumbLink href="/">Home</BreadcrumbLink>
|
|
6901
|
+
* </BreadcrumbItem>
|
|
6902
|
+
* <BreadcrumbSeparator />
|
|
6903
|
+
* <BreadcrumbItem>
|
|
6904
|
+
* <BreadcrumbEllipsis />
|
|
6905
|
+
* </BreadcrumbItem>
|
|
6906
|
+
* <BreadcrumbSeparator />
|
|
6907
|
+
* <BreadcrumbItem>
|
|
6908
|
+
* <BreadcrumbPage>Invoice 4021</BreadcrumbPage>
|
|
6909
|
+
* </BreadcrumbItem>
|
|
6910
|
+
* </BreadcrumbList>
|
|
6911
|
+
* </Breadcrumb>
|
|
6912
|
+
* ```
|
|
6913
|
+
*
|
|
6914
|
+
* **Router links.** `BreadcrumbLink` renders an `<a>` by default. Pass
|
|
6915
|
+
* `render` with the router's link component and the class name, `href` and
|
|
6916
|
+
* handlers are merged onto it, the same contract as `ButtonLink`:
|
|
6917
|
+
* `render={<NextLink href="/projects" />}` or
|
|
6918
|
+
* `render={<Link to="/projects" />}`. This is deliberately not Base UI's
|
|
6919
|
+
* `render` — a breadcrumb is markup, not a Base UI primitive — but it takes
|
|
6920
|
+
* the same shape so there is one thing to remember.
|
|
6921
|
+
*/
|
|
6922
|
+
function Breadcrumb({ className, ...props }) {
|
|
6923
|
+
return /* @__PURE__ */ jsx("nav", {
|
|
6924
|
+
"data-slot": "breadcrumb",
|
|
6925
|
+
"aria-label": "Breadcrumb",
|
|
6926
|
+
className: cn("min-w-0", className),
|
|
6927
|
+
...props
|
|
6928
|
+
});
|
|
6929
|
+
}
|
|
6930
|
+
function BreadcrumbList({ className, ...props }) {
|
|
6931
|
+
return /* @__PURE__ */ jsx("ol", {
|
|
6932
|
+
"data-slot": "breadcrumb-list",
|
|
6933
|
+
className: cn("flex flex-wrap items-center gap-1.5 break-words p-0 sm:gap-2", "list-none text-[length:var(--ds-text-caption-lg)]", "leading-[var(--ds-text-caption-lg--line-height)] text-[color:var(--ds-muted-foreground)]", className),
|
|
6934
|
+
...props
|
|
6935
|
+
});
|
|
6936
|
+
}
|
|
6937
|
+
function BreadcrumbItem({ className, ...props }) {
|
|
6938
|
+
return /* @__PURE__ */ jsx("li", {
|
|
6939
|
+
"data-slot": "breadcrumb-item",
|
|
6940
|
+
className: cn("inline-flex min-w-0 items-center gap-1.5", className),
|
|
6941
|
+
...props
|
|
6942
|
+
});
|
|
6943
|
+
}
|
|
6944
|
+
function BreadcrumbLink({ className, render, children, ...props }) {
|
|
6945
|
+
return renderWith(render, {
|
|
6946
|
+
...props,
|
|
6947
|
+
"data-slot": "breadcrumb-link",
|
|
6948
|
+
className: cn("truncate rounded-[var(--ds-radius-sm)] text-[color:var(--ds-muted-foreground)] no-underline", "transition-colors duration-[var(--ds-duration-fast)] ease-[var(--ds-ease-out)]", "hover:text-[color:var(--ds-foreground)] hover:underline underline-offset-4", "outline-none focus-visible:ring-[3px] focus-visible:ring-[var(--ds-ring)]/40", "[&_svg]:size-3.5 [&_svg]:shrink-0", className)
|
|
6949
|
+
}, children, "a");
|
|
6950
|
+
}
|
|
6951
|
+
/**
|
|
6952
|
+
* The current page: the last crumb, which is not a link.
|
|
6953
|
+
*
|
|
6954
|
+
* A plain `<span aria-current="page">`, deliberately not `role="link"` with
|
|
6955
|
+
* `aria-disabled` — a disabled link that cannot be focused is a fiction, and
|
|
6956
|
+
* it makes `getByRole("link")` return a crumb that navigates nowhere. With a
|
|
6957
|
+
* span, the roles in the trail are exactly the crumbs you can travel to.
|
|
6958
|
+
*/
|
|
6959
|
+
function BreadcrumbPage({ className, ...props }) {
|
|
6960
|
+
return /* @__PURE__ */ jsx("span", {
|
|
6961
|
+
"data-slot": "breadcrumb-page",
|
|
6962
|
+
"aria-current": "page",
|
|
6963
|
+
className: cn("truncate font-medium text-[color:var(--ds-foreground)]", className),
|
|
6964
|
+
...props
|
|
6965
|
+
});
|
|
6966
|
+
}
|
|
6967
|
+
/** Decorative divider between two crumbs; a chevron unless children replace it. */
|
|
6968
|
+
function BreadcrumbSeparator({ className, children, ...props }) {
|
|
6969
|
+
return /* @__PURE__ */ jsx("li", {
|
|
6970
|
+
"data-slot": "breadcrumb-separator",
|
|
6971
|
+
role: "presentation",
|
|
6972
|
+
"aria-hidden": "true",
|
|
6973
|
+
className: cn("inline-flex shrink-0 items-center text-[color:var(--ds-text-tertiary)] [&_svg]:size-3.5", className),
|
|
6974
|
+
...props,
|
|
6975
|
+
children: children ?? /* @__PURE__ */ jsx(ChevronRight, {})
|
|
6976
|
+
});
|
|
6977
|
+
}
|
|
6978
|
+
/**
|
|
6979
|
+
* Stands in for the crumbs a long trail collapses; put it inside a
|
|
6980
|
+
* BreadcrumbItem. The glyph is hidden and the label is not: an ellipsis that
|
|
6981
|
+
* announces nothing leaves a screen-reader user with a gap in the path.
|
|
6982
|
+
*/
|
|
6983
|
+
function BreadcrumbEllipsis({ className, children, ...props }) {
|
|
6984
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
6985
|
+
"data-slot": "breadcrumb-ellipsis",
|
|
6986
|
+
className: cn("inline-flex size-5 items-center justify-center text-[color:var(--ds-text-tertiary)]", "[&_svg]:size-3.5", className),
|
|
6987
|
+
...props,
|
|
6988
|
+
children: [/* @__PURE__ */ jsx(MoreHorizontal, { "aria-hidden": true }), /* @__PURE__ */ jsx("span", {
|
|
6989
|
+
className: "sr-only",
|
|
6990
|
+
children: children ?? "More levels"
|
|
6991
|
+
})]
|
|
6992
|
+
});
|
|
6993
|
+
}
|
|
6994
|
+
//#endregion
|
|
6747
6995
|
//#region src/components/chip.tsx
|
|
6748
6996
|
/**
|
|
6749
6997
|
* Chip — a pill for filters, tags and selected values. Unlike Badge it keeps
|
|
@@ -7299,6 +7547,30 @@ function DateRangePicker(props) {
|
|
|
7299
7547
|
* `onFiles` receives only the accepted files; rejections go to `onReject`.
|
|
7300
7548
|
* `FileList` and `formatFileSize` are separate parts for listing what was
|
|
7301
7549
|
* picked, so a form can keep the zone and the list in different places.
|
|
7550
|
+
*
|
|
7551
|
+
* ## Wrapping a whole page as a drop target
|
|
7552
|
+
*
|
|
7553
|
+
* `noClick` and `noKeyboard` turn off the two activators that only make sense
|
|
7554
|
+
* on a dashed box: clicking anywhere inside opens the file dialog, and Enter /
|
|
7555
|
+
* Space on the focused root does the same. A page-sized zone wraps content
|
|
7556
|
+
* that has its own buttons and inputs, so both have to go — otherwise every
|
|
7557
|
+
* click in the page opens a file picker.
|
|
7558
|
+
*
|
|
7559
|
+
* ```tsx
|
|
7560
|
+
* <Dropzone noClick noKeyboard onFiles={upload} className="min-h-dvh border-0 bg-transparent p-0">
|
|
7561
|
+
* {({ isDragActive, open }) => (
|
|
7562
|
+
* <>
|
|
7563
|
+
* <PageContent />
|
|
7564
|
+
* <Button onClick={open}>Browse…</Button>
|
|
7565
|
+
* {isDragActive ? <DropHint /> : null}
|
|
7566
|
+
* </>
|
|
7567
|
+
* )}
|
|
7568
|
+
* </Dropzone>
|
|
7569
|
+
* ```
|
|
7570
|
+
*
|
|
7571
|
+
* The render-prop form gets react-dropzone's `open()`, which is the way back
|
|
7572
|
+
* to the file dialog from a deliberate control. With `noClick` the root also
|
|
7573
|
+
* drops its `cursor-pointer`, since it is no longer clickable.
|
|
7302
7574
|
*/
|
|
7303
7575
|
const UNITS = [
|
|
7304
7576
|
"B",
|
|
@@ -7332,13 +7604,15 @@ function describeAccept(accept) {
|
|
|
7332
7604
|
}
|
|
7333
7605
|
return exts.size > 0 ? [...exts].join(", ") : void 0;
|
|
7334
7606
|
}
|
|
7335
|
-
function Dropzone({ onFiles, onReject, accept, multiple = true, maxSize, maxFiles, disabled = false, label, hint, children, className, ref, ...props }) {
|
|
7607
|
+
function Dropzone({ onFiles, onReject, accept, multiple = true, maxSize, maxFiles, disabled = false, noClick = false, noKeyboard = false, label, hint, children, className, ref, ...props }) {
|
|
7336
7608
|
const state = useDropzone({
|
|
7337
7609
|
accept,
|
|
7338
7610
|
multiple,
|
|
7339
7611
|
maxSize,
|
|
7340
7612
|
maxFiles,
|
|
7341
7613
|
disabled,
|
|
7614
|
+
noClick,
|
|
7615
|
+
noKeyboard,
|
|
7342
7616
|
onDropAccepted: (files) => onFiles(files),
|
|
7343
7617
|
onDropRejected: (rejections) => onReject?.(rejections)
|
|
7344
7618
|
});
|
|
@@ -7373,7 +7647,7 @@ function Dropzone({ onFiles, onReject, accept, multiple = true, maxSize, maxFile
|
|
|
7373
7647
|
...getRootProps({
|
|
7374
7648
|
...props,
|
|
7375
7649
|
ref: setRoot,
|
|
7376
|
-
className: cn("group/dropzone flex flex-col items-center justify-center gap-2 p-6 text-center", "rounded-[var(--ds-radius-lg)] border border-dashed border-[var(--ds-border)] bg-[var(--ds-card)]", "cursor-pointer select-none outline-none", "transition-[border-color,background-color] duration-[var(--ds-duration-fast)] ease-[var(--ds-ease-out)]", "hover:border-[var(--ds-border-strong)] hover:bg-[var(--ds-hover)]", "focus-visible:border-[var(--ds-ring)] focus-visible:ring-[3px] focus-visible:ring-[var(--ds-ring)]/40", "data-[active]:border-[var(--ds-primary)] data-[active]:bg-[var(--ds-primary-soft)]", "data-[reject]:border-[var(--ds-destructive)] data-[reject]:bg-[var(--ds-destructive-soft)]", "data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className)
|
|
7650
|
+
className: cn("group/dropzone flex flex-col items-center justify-center gap-2 p-6 text-center", "rounded-[var(--ds-radius-lg)] border border-dashed border-[var(--ds-border)] bg-[var(--ds-card)]", noClick ? "select-none outline-none" : "cursor-pointer select-none outline-none", "transition-[border-color,background-color] duration-[var(--ds-duration-fast)] ease-[var(--ds-ease-out)]", "hover:border-[var(--ds-border-strong)] hover:bg-[var(--ds-hover)]", "focus-visible:border-[var(--ds-ring)] focus-visible:ring-[3px] focus-visible:ring-[var(--ds-ring)]/40", "data-[active]:border-[var(--ds-primary)] data-[active]:bg-[var(--ds-primary-soft)]", "data-[reject]:border-[var(--ds-destructive)] data-[reject]:bg-[var(--ds-destructive-soft)]", "data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className)
|
|
7377
7651
|
}),
|
|
7378
7652
|
"data-slot": "dropzone",
|
|
7379
7653
|
"data-active": isDragActive || void 0,
|
|
@@ -7381,6 +7655,8 @@ function Dropzone({ onFiles, onReject, accept, multiple = true, maxSize, maxFile
|
|
|
7381
7655
|
"data-reject": isDragReject || void 0,
|
|
7382
7656
|
"data-focused": isFocused || void 0,
|
|
7383
7657
|
"data-disabled": disabled || void 0,
|
|
7658
|
+
"data-no-click": noClick || void 0,
|
|
7659
|
+
"data-no-keyboard": noKeyboard || void 0,
|
|
7384
7660
|
children: [/* @__PURE__ */ jsx("input", {
|
|
7385
7661
|
"data-slot": "dropzone-input",
|
|
7386
7662
|
...getInputProps()
|
|
@@ -7760,9 +8036,35 @@ function Segmented({ className, value, onValueChange, options, "aria-label": ari
|
|
|
7760
8036
|
* Description, Close); only the Popup's placement differs, chosen by `side`.
|
|
7761
8037
|
* `SheetContent` composes Portal + Backdrop + Popup so consumers keep writing
|
|
7762
8038
|
* `<SheetContent side="right">…</SheetContent>`.
|
|
8039
|
+
*
|
|
8040
|
+
* ## Non-modal side panels
|
|
8041
|
+
*
|
|
8042
|
+
* `modal={false}` is the help-panel / inspector case: a sheet read *alongside*
|
|
8043
|
+
* the app rather than instead of it. No backdrop is rendered, focus is not
|
|
8044
|
+
* trapped, page scroll is not locked, and the rest of the page stays clickable,
|
|
8045
|
+
* so a user can keep working with the panel open. `modal="trap-focus"` is the
|
|
8046
|
+
* middle setting Base UI offers: focus stays inside, the page still scrolls.
|
|
8047
|
+
*
|
|
8048
|
+
* ```tsx
|
|
8049
|
+
* <Sheet modal={false} open={helpOpen} onOpenChange={setHelpOpen}>
|
|
8050
|
+
* <SheetContent side="right" disablePointerDismissal>…</SheetContent>
|
|
8051
|
+
* </Sheet>
|
|
8052
|
+
* ```
|
|
8053
|
+
*
|
|
8054
|
+
* A non-modal sheet closes when focus or a press leaves it; pass
|
|
8055
|
+
* `disablePointerDismissal` (a Base UI Root prop, forwarded) to keep it open
|
|
8056
|
+
* until the user closes it. `modal` is on the Root because that is where Base
|
|
8057
|
+
* UI reads it; `SheetContent` picks the backdrop up from there through context.
|
|
7763
8058
|
*/
|
|
7764
|
-
|
|
7765
|
-
|
|
8059
|
+
const SheetModalContext = React.createContext(true);
|
|
8060
|
+
function Sheet({ modal = true, ...props }) {
|
|
8061
|
+
return /* @__PURE__ */ jsx(SheetModalContext.Provider, {
|
|
8062
|
+
value: modal,
|
|
8063
|
+
children: /* @__PURE__ */ jsx(Dialog$1.Root, {
|
|
8064
|
+
modal,
|
|
8065
|
+
...props
|
|
8066
|
+
})
|
|
8067
|
+
});
|
|
7766
8068
|
}
|
|
7767
8069
|
function SheetTrigger(props) {
|
|
7768
8070
|
return /* @__PURE__ */ jsx(Dialog$1.Trigger, {
|
|
@@ -7804,12 +8106,14 @@ const sheetVariants = cva([
|
|
|
7804
8106
|
defaultVariants: { side: "right" }
|
|
7805
8107
|
});
|
|
7806
8108
|
function SheetContent({ side = "right", className, children, keepMounted, container, ...props }) {
|
|
8109
|
+
const modal = React.useContext(SheetModalContext);
|
|
7807
8110
|
return /* @__PURE__ */ jsxs(SheetPortal, {
|
|
7808
8111
|
keepMounted,
|
|
7809
8112
|
container,
|
|
7810
|
-
children: [/* @__PURE__ */ jsx(SheetOverlay, {}), /* @__PURE__ */ jsx(Dialog$1.Popup, {
|
|
8113
|
+
children: [modal === false ? null : /* @__PURE__ */ jsx(SheetOverlay, {}), /* @__PURE__ */ jsx(Dialog$1.Popup, {
|
|
7811
8114
|
"data-slot": "sheet-content",
|
|
7812
8115
|
"data-side": side,
|
|
8116
|
+
"data-modal": modal === false ? void 0 : modal === true ? "" : modal,
|
|
7813
8117
|
className: cn(sheetVariants({ side }), className),
|
|
7814
8118
|
...props,
|
|
7815
8119
|
children
|
|
@@ -7846,6 +8150,40 @@ function SheetDescription({ className, ...props }) {
|
|
|
7846
8150
|
}
|
|
7847
8151
|
//#endregion
|
|
7848
8152
|
//#region src/components/sortable-list.tsx
|
|
8153
|
+
/**
|
|
8154
|
+
* SortableList.
|
|
8155
|
+
*
|
|
8156
|
+
* A reorderable list over dnd-kit: `DndContext` + `SortableContext` around one
|
|
8157
|
+
* `useSortable` item per entry. The list owns nothing — it calls `onReorder`
|
|
8158
|
+
* with the next array and the consumer stores it. Pointer and keyboard sensors
|
|
8159
|
+
* are wired (Space picks up, arrows move, Space drops, Escape cancels) and a
|
|
8160
|
+
* `DragOverlay` paints the lifted copy with `--ds-shadow-lg` while the item
|
|
8161
|
+
* left behind dims and takes the ring colour.
|
|
8162
|
+
*
|
|
8163
|
+
* By default the whole row is the drag activator. Pass `handle` to restrict
|
|
8164
|
+
* dragging to a `<SortableHandle>` (or any element given `handleProps`) so
|
|
8165
|
+
* buttons and inputs inside a row stay clickable.
|
|
8166
|
+
*
|
|
8167
|
+
* ## Touch
|
|
8168
|
+
*
|
|
8169
|
+
* A pointer drag and a touch scroll start the same way, so something has to
|
|
8170
|
+
* say which one a finger means. In handle mode only the small handle is
|
|
8171
|
+
* `touch-none`, so the rest of the row scrolls: nothing to decide. In
|
|
8172
|
+
* whole-row mode the whole row is `touch-none`, which is why a touch list
|
|
8173
|
+
* whose rows are the activators cannot be scrolled by dragging over them.
|
|
8174
|
+
*
|
|
8175
|
+
* `touchScroll` is the way out, and it defaults to whichever of those is
|
|
8176
|
+
* already true — `true` in handle mode, `false` in whole-row mode, so existing
|
|
8177
|
+
* lists behave exactly as before. Setting it `true` on a whole-row list drops
|
|
8178
|
+
* `touch-none` and swaps the PointerSensor for a MouseSensor plus a
|
|
8179
|
+
* TouchSensor with delay activation: a quick swipe scrolls, a press held for
|
|
8180
|
+
* {@link TOUCH_DELAY_MS} picks the row up. `false` in handle mode is the
|
|
8181
|
+
* opposite trade — the row never scrolls under a finger.
|
|
8182
|
+
*/
|
|
8183
|
+
/** How long a finger must rest on a row before it becomes a drag. */
|
|
8184
|
+
const TOUCH_DELAY_MS = 250;
|
|
8185
|
+
/** How far it may slip in that time and still count as a press, not a scroll. */
|
|
8186
|
+
const TOUCH_TOLERANCE_PX = 8;
|
|
7849
8187
|
/** dnd-kit types its listeners as a bag of `Function`s; narrow them to the handlers they are. */
|
|
7850
8188
|
function asHandlers(listeners) {
|
|
7851
8189
|
return listeners ?? {};
|
|
@@ -7858,7 +8196,7 @@ const SortableItemContext = React.createContext({
|
|
|
7858
8196
|
disabled: false
|
|
7859
8197
|
});
|
|
7860
8198
|
const itemClassName = cn("relative rounded-[var(--ds-radius-md)] outline-none", "focus-visible:ring-[3px] focus-visible:ring-[var(--ds-ring)]/40", "data-[dragging]:opacity-50 data-[dragging]:ring-2 data-[dragging]:ring-[var(--ds-ring)]");
|
|
7861
|
-
function SortableItem({ id, item, handle, disabled, renderItem, className }) {
|
|
8199
|
+
function SortableItem({ id, item, handle, disabled, touchScroll, renderItem, className }) {
|
|
7862
8200
|
const { attributes, listeners, setNodeRef, setActivatorNodeRef, transform, transition, isDragging } = useSortable({
|
|
7863
8201
|
id,
|
|
7864
8202
|
disabled
|
|
@@ -7896,7 +8234,7 @@ function SortableItem({ id, item, handle, disabled, renderItem, className }) {
|
|
|
7896
8234
|
transform: CSS.Translate.toString(transform),
|
|
7897
8235
|
transition
|
|
7898
8236
|
},
|
|
7899
|
-
className: cn(itemClassName, !handle && !disabled && "cursor-grab
|
|
8237
|
+
className: cn(itemClassName, !handle && !disabled && "cursor-grab data-[dragging]:cursor-grabbing", !touchScroll && !disabled && "touch-none", className),
|
|
7900
8238
|
...rowActivator,
|
|
7901
8239
|
children: renderItem(item, {
|
|
7902
8240
|
handleProps,
|
|
@@ -7923,9 +8261,19 @@ function SortableHandle({ className, children, ...props }) {
|
|
|
7923
8261
|
children: children ?? /* @__PURE__ */ jsx(GripVertical, { "aria-hidden": true })
|
|
7924
8262
|
});
|
|
7925
8263
|
}
|
|
7926
|
-
function SortableList({ items, getId, onReorder, renderItem, orientation = "vertical", handle = false, disabled = false, itemClassName: itemClass, className, ...props }) {
|
|
8264
|
+
function SortableList({ items, getId, onReorder, renderItem, orientation = "vertical", handle = false, disabled = false, touchScroll = handle, itemClassName: itemClass, className, ...props }) {
|
|
7927
8265
|
const [activeId, setActiveId] = React.useState(null);
|
|
7928
|
-
const
|
|
8266
|
+
const delayTouch = touchScroll && !handle;
|
|
8267
|
+
const pointerSensor = useSensor(PointerSensor, { activationConstraint: { distance: 4 } });
|
|
8268
|
+
const mouseSensor = useSensor(MouseSensor, { activationConstraint: { distance: 4 } });
|
|
8269
|
+
const touchSensor = useSensor(TouchSensor, { activationConstraint: {
|
|
8270
|
+
delay: TOUCH_DELAY_MS,
|
|
8271
|
+
tolerance: TOUCH_TOLERANCE_PX
|
|
8272
|
+
} });
|
|
8273
|
+
const keyboardSensor = useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates });
|
|
8274
|
+
const pointerSensors = useSensors(pointerSensor, keyboardSensor);
|
|
8275
|
+
const splitSensors = useSensors(mouseSensor, touchSensor, keyboardSensor);
|
|
8276
|
+
const sensors = delayTouch ? splitSensors : pointerSensors;
|
|
7929
8277
|
const ids = React.useMemo(() => items.map(getId), [items, getId]);
|
|
7930
8278
|
const activeItem = activeId === null ? void 0 : items[ids.indexOf(activeId)];
|
|
7931
8279
|
const onDragStart = React.useCallback((event) => {
|
|
@@ -7938,7 +8286,12 @@ function SortableList({ items, getId, onReorder, renderItem, orientation = "vert
|
|
|
7938
8286
|
const from = ids.indexOf(active.id);
|
|
7939
8287
|
const to = ids.indexOf(over.id);
|
|
7940
8288
|
if (from < 0 || to < 0) return;
|
|
7941
|
-
onReorder(arrayMove([...items], from, to)
|
|
8289
|
+
onReorder(arrayMove([...items], from, to), {
|
|
8290
|
+
from,
|
|
8291
|
+
to,
|
|
8292
|
+
activeId: active.id,
|
|
8293
|
+
overId: over.id
|
|
8294
|
+
});
|
|
7942
8295
|
}, [
|
|
7943
8296
|
ids,
|
|
7944
8297
|
items,
|
|
@@ -7959,6 +8312,7 @@ function SortableList({ items, getId, onReorder, renderItem, orientation = "vert
|
|
|
7959
8312
|
"data-slot": "sortable-list",
|
|
7960
8313
|
"data-orientation": orientation,
|
|
7961
8314
|
"data-disabled": disabled || void 0,
|
|
8315
|
+
"data-touch-scroll": touchScroll ? "" : void 0,
|
|
7962
8316
|
className: cn("flex list-none gap-2 p-0", orientation === "horizontal" ? "flex-row flex-wrap" : "flex-col", className),
|
|
7963
8317
|
...props,
|
|
7964
8318
|
children: items.map((item, index) => /* @__PURE__ */ jsx(SortableItem, {
|
|
@@ -7966,6 +8320,7 @@ function SortableList({ items, getId, onReorder, renderItem, orientation = "vert
|
|
|
7966
8320
|
item,
|
|
7967
8321
|
handle,
|
|
7968
8322
|
disabled,
|
|
8323
|
+
touchScroll,
|
|
7969
8324
|
renderItem,
|
|
7970
8325
|
className: itemClass
|
|
7971
8326
|
}, ids[index] ?? index))
|
|
@@ -8312,6 +8667,6 @@ function useCortenaTheme(options = {}) {
|
|
|
8312
8667
|
};
|
|
8313
8668
|
}
|
|
8314
8669
|
//#endregion
|
|
8315
|
-
export { A2UIErrorCard, A2UIRenderer, A2UI_CATALOGUE_ID, A2UI_DEFAULT_SURFACE_ID, A2UI_VERSION, Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertIcon, AlertTitle, Area, AreaChart, Avatar, AvatarFallback, AvatarImage, Badge, Bar, BarChart, Button, ButtonLink, Calendar, CalendarDayButton, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CartesianGrid, Cell, Chart, ChartContainer, ChartEmpty, ChartError, ChartLegend, ChartLegendContent, ChartLoading, ChartTooltip, ChartTooltipContent, Checkbox, Chip, Combobox, ComboboxChip, ComboboxChips, ComboboxClear, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, ComboboxItem, ComboboxSeparator, ComboboxStatus, ComboboxTrigger, ComboboxValue, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandLoading, CommandSeparator, CommandShortcut, ComposedChart, DEFAULT_THEME_STORAGE_KEY, DataTable, DataTableColumnHeader, DataTableExportMenu, DataTableFacetedFilter, DataTablePagination, DataTableToolbar, DataTableView, DataTableViewOptions, DateField, DatePicker, DateRangePicker, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Dropzone, EmptyState, ErrorBanner, Field, FieldContent, FieldControl, FieldDescription, FieldError, FieldGroup, FieldLabel, Fieldset, FieldsetLegend, FileList, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, Funnel, FunnelChart, Input, Kbd, Label, LabelList, Line, LineChart, LoadingSkeleton, Markdown, NIVO_TYPES, PageHeader, Pie, PieChart, PolarAngleAxis, PolarGrid, PolarRadiusAxis, Popover, PopoverClose, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger, Progress, ProgressIndicator, ProgressLabel, ProgressTrack, ProgressValue, RECHARTS_TYPES, Radar, RadarChart, RadioGroup, RadioGroupItem, RechartsLegend, RechartsTooltip, ReferenceLine, ResponsiveContainer, Scatter, ScatterChart, ScrollArea, ScrollBar, SectionCard, Segmented, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Skeleton, SortableHandle, SortableList, Spinner, StatusDot, Switch, THEME_MESSAGE_TYPE, Tabs, TabsContent, TabsIndicator, TabsList, TabsTrigger, Textarea, Toast, Toaster, Toolbar, ToolbarEnd, ToolbarSeparator, ToolbarStart, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, VIZ_SERIES_COUNT, XAxis, YAxis, alertVariants, applyStoredTheme, applyTheme, arrayMove, badgeVariants, buildCatalogueDoc, buttonVariants, catalogueMarkdown, catalogueNames, chartEngine, chartScales, chipVariants, cn, createColumnHelper, dataTableFeatures, defaultCatalogue, downloadCsv, downloadExcel, exampleMessages, fieldVariants, foldMessages, formatDateDefault, formatDateISO, formatDateLong, formatDateShort, formatFileSize, formatRelative, getAtPointer, getThemeInitScript, inputClassName, isDataBinding, labelVariants, markdownSanitizeSchema, nivoTheme, parseA2UIMessages, parseDateDefault, parseDateISO, pointerSegments, readAction, readChildren, readComponent, readStoredTheme, resolveColor, resolvePointer, resolveValue, resolveVizSeries, seriesColor, setAtPointer, sheetVariants, textareaClassName, themeFromBackground, themeFromMessage, themeInitScript, toCsv, toHex, toSheet, toastVariants, useChart, useComboboxFilter, useCortenaTheme, useDataTable, useForm, useFormField, useNivoTheme, useToast, vizSeriesVars, vizVar, zodResolver };
|
|
8670
|
+
export { A2UIErrorCard, A2UIRenderer, A2UI_CATALOGUE_ID, A2UI_DEFAULT_SURFACE_ID, A2UI_VERSION, Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertIcon, AlertTitle, Area, AreaChart, Avatar, AvatarFallback, AvatarImage, Badge, Bar, BarChart, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonLink, Calendar, CalendarDayButton, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CartesianGrid, Cell, Chart, ChartContainer, ChartEmpty, ChartError, ChartLegend, ChartLegendContent, ChartLoading, ChartTooltip, ChartTooltipContent, Checkbox, Chip, Combobox, ComboboxChip, ComboboxChips, ComboboxClear, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, ComboboxItem, ComboboxSeparator, ComboboxStatus, ComboboxTrigger, ComboboxValue, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandLoading, CommandSeparator, CommandShortcut, ComposedChart, DEFAULT_THEME_STORAGE_KEY, DataTable, DataTableColumnHeader, DataTableExportMenu, DataTableFacetedFilter, DataTablePagination, DataTableToolbar, DataTableView, DataTableViewOptions, DateField, DatePicker, DateRangePicker, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Dropzone, EmptyState, ErrorBanner, Field, FieldContent, FieldControl, FieldDescription, FieldError, FieldGroup, FieldLabel, Fieldset, FieldsetLegend, FileList, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, Funnel, FunnelChart, Input, Kbd, Label, LabelList, Line, LineChart, LoadingSkeleton, Markdown, NIVO_TYPES, PageHeader, Pie, PieChart, PolarAngleAxis, PolarGrid, PolarRadiusAxis, Popover, PopoverClose, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger, Progress, ProgressIndicator, ProgressLabel, ProgressTrack, ProgressValue, RECHARTS_TYPES, Radar, RadarChart, RadioGroup, RadioGroupItem, RechartsLegend, RechartsTooltip, ReferenceLine, ResponsiveContainer, Scatter, ScatterChart, ScrollArea, ScrollBar, SectionCard, Segmented, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Skeleton, SortableHandle, SortableList, Spinner, StatusDot, Switch, THEME_MESSAGE_TYPE, Tabs, TabsContent, TabsIndicator, TabsList, TabsTrigger, Textarea, Toast, Toaster, Toolbar, ToolbarEnd, ToolbarSeparator, ToolbarStart, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, VIZ_SERIES_COUNT, XAxis, YAxis, alertVariants, applyStoredTheme, applyTheme, arrayMove, badgeVariants, buildCatalogueDoc, buttonVariants, catalogueMarkdown, catalogueNames, chartEngine, chartScales, chipVariants, cn, createColumnHelper, dataTableFeatures, defaultCatalogue, downloadCsv, downloadExcel, exampleMessages, fieldVariants, foldMessages, formatDateDefault, formatDateISO, formatDateLong, formatDateShort, formatFileSize, formatRelative, getAtPointer, getThemeInitScript, inputClassName, isDataBinding, labelVariants, markdownSanitizeSchema, nivoTheme, parseA2UIMessages, parseDateDefault, parseDateISO, pointerSegments, readAction, readChildren, readComponent, readStoredTheme, resolveColor, resolvePointer, resolveValue, resolveVizSeries, seriesColor, setAtPointer, sheetVariants, textareaClassName, themeFromBackground, themeFromMessage, themeInitScript, toCsv, toHex, toSheet, toastVariants, useChart, useComboboxFilter, useCortenaTheme, useDataTable, useForm, useFormField, useNivoTheme, useToast, vizSeriesVars, vizVar, zodResolver };
|
|
8316
8671
|
|
|
8317
8672
|
//# sourceMappingURL=index.js.map
|