basalt-ui 2.6.1 → 2.7.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/AGENTS.md +15 -15
- package/CHANGELOG.md +16 -0
- package/MIGRATING.md +38 -12
- package/agent/rules/basalt-batteries.md +1 -1
- package/agent/rules/basalt-controls.md +1 -1
- package/configs/oxlint-plugin.js +48 -0
- package/configs/oxlint-plugin.test.ts +82 -0
- package/dist/controls/form-layout.d.ts +15 -6
- package/dist/controls/form-layout.d.ts.map +1 -1
- package/dist/forms/field.d.ts +42 -2
- package/dist/forms/field.d.ts.map +1 -1
- package/dist/forms/field.js +2 -2
- package/dist/forms/index.d.ts +4 -5
- package/dist/forms/index.d.ts.map +1 -1
- package/dist/surfaces.d.ts +1 -1
- package/dist/surfaces.js +1 -1
- package/dist/table/data-table.d.ts +33 -0
- package/dist/table/data-table.d.ts.map +1 -1
- package/dist/table/data-table.js +100 -17
- package/llms.txt +237 -4
- package/package.json +1 -1
- package/src/controls/form-layout.tsx +15 -6
- package/src/forms/field.ts +78 -3
- package/src/forms/index.ts +4 -5
- package/src/surfaces.ts +1 -1
- package/src/table/data-table.tsx +171 -17
|
@@ -51,6 +51,19 @@ export type DataTableColumnPinning<T = unknown> = {
|
|
|
51
51
|
start?: DataTableColumnId<T>[];
|
|
52
52
|
end?: DataTableColumnId<T>[];
|
|
53
53
|
};
|
|
54
|
+
/** One per-row action: `BarActionItem`'s vocabulary with the row handed to the handler. */
|
|
55
|
+
export type DataTableRowAction<T = unknown> = {
|
|
56
|
+
key: string;
|
|
57
|
+
label: string;
|
|
58
|
+
/** A lone action with an icon renders as that icon button; anything else folds into the menu. */
|
|
59
|
+
icon?: ReactNode;
|
|
60
|
+
onClick: (row: T) => void;
|
|
61
|
+
danger?: boolean;
|
|
62
|
+
/** A disabled action renders inert and never fires. */
|
|
63
|
+
disabled?: (row: T) => boolean;
|
|
64
|
+
/** A loading action shows the busy state (icon button) or sits inert (menu) and never fires. */
|
|
65
|
+
loading?: (row: T) => boolean;
|
|
66
|
+
};
|
|
54
67
|
/**
|
|
55
68
|
* The four boxes `BasaltDataTable` paints: `root` is the outer fragment's replacement wrapper,
|
|
56
69
|
* `toolbar` is the search/facets/actions row, `table` is whichever body renders — the Mantine
|
|
@@ -316,6 +329,26 @@ export type BasaltDataTableProps<T extends RowData> = BasaltProps & SlotStylesPr
|
|
|
316
329
|
* ]}
|
|
317
330
|
*/
|
|
318
331
|
bulkActions?: (rows: T[]) => BarAction[];
|
|
332
|
+
/**
|
|
333
|
+
* Per-row actions as typed data. The table renders them itself in a trailing, pinned,
|
|
334
|
+
* header-less column: an icon button for one action that carries an `icon`, an overflow menu
|
|
335
|
+
* for anything else. Clicking either never fires `onRowActivate`. Never put a `Menu` or
|
|
336
|
+
* `ActionIcon` in a `display` / `cell` renderer (`basalt/control-outside-home`).
|
|
337
|
+
*
|
|
338
|
+
* Pass a STABLE reference — a module constant or a `useMemo` — because the column is rebuilt
|
|
339
|
+
* whenever the array identity changes. A `renderCard` projection owns its own card, so the
|
|
340
|
+
* column renders in the table body only.
|
|
341
|
+
*
|
|
342
|
+
* @example
|
|
343
|
+
* const ROW_ACTIONS: DataTableRowAction<Row>[] = [
|
|
344
|
+
* { key: 'edit', label: 'Edit', icon: <IconEdit />, onClick: (row) => edit(row) },
|
|
345
|
+
* { key: 'delete', label: 'Delete', danger: true, onClick: (row) => remove(row) },
|
|
346
|
+
* ]
|
|
347
|
+
* <BasaltDataTable rowActions={ROW_ACTIONS} rowLabel={(row) => row.name} … />
|
|
348
|
+
*/
|
|
349
|
+
rowActions?: DataTableRowAction<T>[];
|
|
350
|
+
/** Names a row for assistive tech in its action controls; default `Row N actions`. */
|
|
351
|
+
rowLabel?: (row: T) => string;
|
|
319
352
|
/**
|
|
320
353
|
* Enables the bottom pagination bar ("Showing X–Y of N", rows-per-page `Select`, Mantine
|
|
321
354
|
* `Pagination`) wired to TanStack's `pagination` state. Client-side by default — see
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../../src/table/data-table.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../../src/table/data-table.tsx"],"names":[],"mappings":"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"}
|
package/dist/table/data-table.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import {
|
|
3
|
+
ActionIcon,
|
|
3
4
|
Box,
|
|
4
5
|
Checkbox,
|
|
5
6
|
Group,
|
|
@@ -21,10 +22,11 @@ import { HIT_COARSE } from "../common/hit-floor.js";
|
|
|
21
22
|
import { useMeasuredWidths } from "../common/use-measured-widths.js";
|
|
22
23
|
import { assertRequiredProps, useValidateProps } from "../common/validate.js";
|
|
23
24
|
import { FilterSet } from "../controls/index.js";
|
|
24
|
-
import { ActionGroup, BarActionSlot } from "../controls/actions.js";
|
|
25
|
+
import { ActionGroup, BarActionSlot, OverflowMenu } from "../controls/actions.js";
|
|
25
26
|
import { EnumFilter } from "../controls/enum-filter.js";
|
|
26
27
|
import { MultiSelectFilter } from "../controls/multi-select-filter.js";
|
|
27
28
|
import { CtlSlot } from "../theme/index.js";
|
|
29
|
+
import { IconSlot } from "../theme/icon-slot.js";
|
|
28
30
|
import { alpha, VX } from "../tokens/index.js";
|
|
29
31
|
import { WidgetHeader } from "../dashboard/index.js";
|
|
30
32
|
import { ErrorState } from "../dashboard/query-state.js";
|
|
@@ -148,6 +150,74 @@ function selectionColumn() {
|
|
|
148
150
|
)
|
|
149
151
|
};
|
|
150
152
|
}
|
|
153
|
+
const ACTIONS_COLUMN_ID = "__basalt_actions__";
|
|
154
|
+
const ACTIONS_COLUMN_SIZE = 56;
|
|
155
|
+
function stopsRowActivation(cell) {
|
|
156
|
+
if (cell.column.id === ACTIONS_COLUMN_ID) return true;
|
|
157
|
+
return cell.column.id === SELECT_COLUMN_ID && cell.row.getCanSelect();
|
|
158
|
+
}
|
|
159
|
+
function RowActionCell({
|
|
160
|
+
actions,
|
|
161
|
+
row,
|
|
162
|
+
rowIndex,
|
|
163
|
+
rowLabel
|
|
164
|
+
}) {
|
|
165
|
+
const named = rowLabel?.(row);
|
|
166
|
+
const [only] = actions;
|
|
167
|
+
if (actions.length === 1 && only?.icon !== void 0) {
|
|
168
|
+
const inert = only.disabled?.(row) === true || only.loading?.(row) === true;
|
|
169
|
+
return /* @__PURE__ */ jsx(
|
|
170
|
+
ActionIcon,
|
|
171
|
+
{
|
|
172
|
+
variant: "subtle",
|
|
173
|
+
size: "ctl",
|
|
174
|
+
"aria-label": named === void 0 ? only.label : `${only.label}: ${named}`,
|
|
175
|
+
disabled: only.disabled?.(row) === true,
|
|
176
|
+
loading: only.loading?.(row) === true,
|
|
177
|
+
...only.danger === true && { color: "red" },
|
|
178
|
+
onClick: () => {
|
|
179
|
+
if (!inert) only.onClick(row);
|
|
180
|
+
},
|
|
181
|
+
children: /* @__PURE__ */ jsx(IconSlot, { children: only.icon })
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
const items = actions.map((action) => ({
|
|
186
|
+
key: action.key,
|
|
187
|
+
label: action.label,
|
|
188
|
+
...action.icon !== void 0 && { icon: action.icon },
|
|
189
|
+
...action.danger === true && { danger: true },
|
|
190
|
+
// The menu has no busy state of its own, so loading reads as inert there.
|
|
191
|
+
disabled: action.disabled?.(row) === true || action.loading?.(row) === true,
|
|
192
|
+
onClick: () => action.onClick(row)
|
|
193
|
+
}));
|
|
194
|
+
return /* @__PURE__ */ jsx(
|
|
195
|
+
OverflowMenu,
|
|
196
|
+
{
|
|
197
|
+
actions: items,
|
|
198
|
+
trigger: "kebab",
|
|
199
|
+
label: named === void 0 ? `Row ${rowIndex + 1} actions` : `Actions for ${named}`
|
|
200
|
+
}
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
function rowActionsColumn(actions, rowLabel) {
|
|
204
|
+
return {
|
|
205
|
+
id: ACTIONS_COLUMN_ID,
|
|
206
|
+
size: ACTIONS_COLUMN_SIZE,
|
|
207
|
+
enableSorting: false,
|
|
208
|
+
enableHiding: false,
|
|
209
|
+
header: () => /* @__PURE__ */ jsx("span", { className: classes.srOnly, children: "Actions" }),
|
|
210
|
+
cell: ({ row }) => /* @__PURE__ */ jsx(
|
|
211
|
+
RowActionCell,
|
|
212
|
+
{
|
|
213
|
+
actions,
|
|
214
|
+
row: row.original,
|
|
215
|
+
rowIndex: row.index,
|
|
216
|
+
rowLabel
|
|
217
|
+
}
|
|
218
|
+
)
|
|
219
|
+
};
|
|
220
|
+
}
|
|
151
221
|
function BulkActionBar({ count, actions }) {
|
|
152
222
|
return /* @__PURE__ */ jsxs(Group, { className: classes.bulkBar, gap: "xs", align: "center", wrap: "wrap", mb: "xs", children: [
|
|
153
223
|
/* @__PURE__ */ jsxs(Text, { className: classes.bulkCount, children: [
|
|
@@ -409,6 +479,8 @@ function BasaltDataTable(props) {
|
|
|
409
479
|
enableRowSelection = false,
|
|
410
480
|
getRowId,
|
|
411
481
|
bulkActions,
|
|
482
|
+
rowActions,
|
|
483
|
+
rowLabel,
|
|
412
484
|
enablePagination = false,
|
|
413
485
|
pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS,
|
|
414
486
|
manualPagination = false,
|
|
@@ -461,9 +533,14 @@ function BasaltDataTable(props) {
|
|
|
461
533
|
return { ...column, filterFn };
|
|
462
534
|
});
|
|
463
535
|
}, [columns, facets]);
|
|
536
|
+
const hasRowActions = rowActions !== void 0 && rowActions.length > 0;
|
|
464
537
|
const tableColumns = useMemo(
|
|
465
|
-
() =>
|
|
466
|
-
|
|
538
|
+
() => [
|
|
539
|
+
...enableRowSelection ? [selectionColumn()] : [],
|
|
540
|
+
...facetColumns,
|
|
541
|
+
...hasRowActions ? [rowActionsColumn(rowActions, rowLabel)] : []
|
|
542
|
+
],
|
|
543
|
+
[facetColumns, enableRowSelection, hasRowActions, rowActions, rowLabel]
|
|
467
544
|
);
|
|
468
545
|
const hasFacets = Boolean(facets && facets.length > 0);
|
|
469
546
|
const breaches = manualPaginationBreaches({
|
|
@@ -512,6 +589,11 @@ function BasaltDataTable(props) {
|
|
|
512
589
|
);
|
|
513
590
|
const hasFolded = foldedColumns.size > 0;
|
|
514
591
|
const foldRows = useRowDisclosure({ data, getRowId });
|
|
592
|
+
const pinningActive = enablePinning || hasRowActions;
|
|
593
|
+
const tablePinning = useMemo(
|
|
594
|
+
() => hasRowActions ? { ...columnPinning, end: [...columnPinning.end, ACTIONS_COLUMN_ID] } : columnPinning,
|
|
595
|
+
[columnPinning, hasRowActions]
|
|
596
|
+
);
|
|
515
597
|
const table = useTable({
|
|
516
598
|
features: basaltTableFeatures,
|
|
517
599
|
data,
|
|
@@ -520,7 +602,7 @@ function BasaltDataTable(props) {
|
|
|
520
602
|
sorting: tableState.sorting,
|
|
521
603
|
globalFilter,
|
|
522
604
|
columnFilters: tableState.columnFilters,
|
|
523
|
-
columnPinning,
|
|
605
|
+
columnPinning: tablePinning,
|
|
524
606
|
columnVisibility,
|
|
525
607
|
...enablePagination && { pagination: tableState.pagination },
|
|
526
608
|
...enableRowSelection && { rowSelection: tableState.rowSelection }
|
|
@@ -549,7 +631,7 @@ function BasaltDataTable(props) {
|
|
|
549
631
|
...manualPagination && pageCount !== void 0 && { pageCount }
|
|
550
632
|
},
|
|
551
633
|
enableSorting: sortingEnabled,
|
|
552
|
-
enableColumnPinning:
|
|
634
|
+
enableColumnPinning: pinningActive
|
|
553
635
|
});
|
|
554
636
|
const showSearch = enableGlobalFilter && filteringEnabled;
|
|
555
637
|
const showFacets = hasFacets && filteringEnabled;
|
|
@@ -557,7 +639,7 @@ function BasaltDataTable(props) {
|
|
|
557
639
|
const branch = query === void 0 ? void 0 : dataQueryBranch("BasaltDataTable", query);
|
|
558
640
|
const showSkeleton = branch === void 0 ? isLoading : branch === "pending";
|
|
559
641
|
const queryError = branch === "error" && query !== void 0 ? query : void 0;
|
|
560
|
-
const columnCount = columns.length + (enableRowSelection ? 1 : 0) + (hasFolded ? 1 : 0) - foldedColumns.size;
|
|
642
|
+
const columnCount = columns.length + (enableRowSelection ? 1 : 0) + (hasRowActions ? 1 : 0) + (hasFolded ? 1 : 0) - foldedColumns.size;
|
|
561
643
|
const selectedModelRows = enableRowSelection ? table.getSelectedRowModel().rows : void 0;
|
|
562
644
|
const selectedRows = useMemo(
|
|
563
645
|
() => selectedModelRows?.map((row) => row.original) ?? [],
|
|
@@ -567,7 +649,7 @@ function BasaltDataTable(props) {
|
|
|
567
649
|
() => bulkActions === void 0 || selectedRows.length === 0 ? void 0 : bulkActions(selectedRows),
|
|
568
650
|
[bulkActions, selectedRows]
|
|
569
651
|
);
|
|
570
|
-
const headerGroups =
|
|
652
|
+
const headerGroups = pinningActive ? getOrderedHeaderGroups(table) : table.getHeaderGroups();
|
|
571
653
|
const rows = table.getRowModel().rows;
|
|
572
654
|
const pageStickyHeader = !scrolls && stickyHeader === true;
|
|
573
655
|
const { wrapperRef: containmentRef, contained } = useMeasuredContainment(
|
|
@@ -610,14 +692,15 @@ function BasaltDataTable(props) {
|
|
|
610
692
|
const canSort = sortingEnabled && header.column.getCanSort();
|
|
611
693
|
const sorted = header.column.getIsSorted();
|
|
612
694
|
const toggleSorting = header.column.getToggleSortingHandler();
|
|
613
|
-
const pinnedStyle =
|
|
695
|
+
const pinnedStyle = pinningActive ? getPinnedCellStyle(table, header.column) : void 0;
|
|
614
696
|
const align = resolveAlign(header.column);
|
|
615
697
|
const isSelectColumn = header.column.id === SELECT_COLUMN_ID;
|
|
698
|
+
const isFoldCandidate = !isSelectColumn && header.column.id !== ACTIONS_COLUMN_ID;
|
|
616
699
|
return /* @__PURE__ */ jsxs(
|
|
617
700
|
Table.Th,
|
|
618
701
|
{
|
|
619
702
|
...isSelectColumn && { className: classes.selectCell },
|
|
620
|
-
|
|
703
|
+
...isFoldCandidate && { [FOLD_ID_ATTR]: header.column.id },
|
|
621
704
|
onClick: canSort ? toggleSorting : void 0,
|
|
622
705
|
onKeyDown: canSort ? (event) => {
|
|
623
706
|
if (event.key !== "Enter" && event.key !== " ") return;
|
|
@@ -641,7 +724,7 @@ function BasaltDataTable(props) {
|
|
|
641
724
|
})
|
|
642
725
|
] }, headerGroup.id)) }),
|
|
643
726
|
/* @__PURE__ */ jsx(Table.Tbody, { children: queryError !== void 0 ? /* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, { colSpan: columnCount, children: errorNode }) }) : showSkeleton ? Array.from({ length: skeletonRows }, (_, rowIndex) => /* @__PURE__ */ jsx(Table.Tr, { children: Array.from({ length: columnCount }, (__, colIndex) => /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Skeleton, { height: 16, radius: "sm" }) }, `skeleton-${rowIndex}-${colIndex}`)) }, `skeleton-${rowIndex}`)) : rows.length === 0 ? /* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, { colSpan: columnCount, children: emptyNode }) }) : rows.map((row) => {
|
|
644
|
-
const cells =
|
|
727
|
+
const cells = pinningActive ? [
|
|
645
728
|
...row.getStartVisibleCells(),
|
|
646
729
|
...row.getCenterVisibleCells(),
|
|
647
730
|
...row.getEndVisibleCells()
|
|
@@ -663,18 +746,18 @@ function BasaltDataTable(props) {
|
|
|
663
746
|
}
|
|
664
747
|
) }),
|
|
665
748
|
cells.map((cell) => {
|
|
666
|
-
const pinnedStyle =
|
|
749
|
+
const pinnedStyle = pinningActive ? getPinnedCellStyle(table, cell.column) : void 0;
|
|
667
750
|
const align = resolveAlign(cell.column);
|
|
668
751
|
return /* @__PURE__ */ jsx(
|
|
669
752
|
Table.Td,
|
|
670
753
|
{
|
|
671
754
|
...cell.column.id === SELECT_COLUMN_ID && {
|
|
672
|
-
className: classes.selectCell
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
755
|
+
className: classes.selectCell
|
|
756
|
+
},
|
|
757
|
+
...stopsRowActivation(cell) && {
|
|
758
|
+
// The label's ::after fills the select cell, so a tap on it bubbles to the
|
|
759
|
+
// row; the actions menu portals out but React bubbles through the portal.
|
|
760
|
+
onClick: (event) => event.stopPropagation()
|
|
678
761
|
},
|
|
679
762
|
style: {
|
|
680
763
|
...typeof cell.getValue() === "number" && cell.column.columnDef.meta?.numeral !== false ? NUMERIC_CELL_STYLE : void 0,
|
package/llms.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# basalt-ui v2.
|
|
1
|
+
# basalt-ui v2.7.0
|
|
2
2
|
# Opinionated framework for Mantine-based React apps — theme, app shell, TanStack Charts, toolchain presets
|
|
3
3
|
#
|
|
4
4
|
# Entry points: use the exact import specifier below; do not guess.
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# A subpath's `Install:` line is its required peers; `OptionalPeers:` are import()-only, install on use.
|
|
14
14
|
|
|
15
15
|
Package: basalt-ui
|
|
16
|
-
Version: 2.
|
|
16
|
+
Version: 2.7.0
|
|
17
17
|
|
|
18
18
|
## basalt-ui
|
|
19
19
|
Import: import { ... } from 'basalt-ui'
|
|
@@ -54,16 +54,206 @@ Description: CartesianChart (the TanStack Charts rung), the Lines and Bars kinds
|
|
|
54
54
|
Layer: headless
|
|
55
55
|
Rule: basalt-charts
|
|
56
56
|
Signature: BandStrip(props: BandStripProps<T, X>): ReactElement<unknown, string | JSXElementConstructor<any>>
|
|
57
|
+
className?: string
|
|
58
|
+
style?: CSSProperties
|
|
59
|
+
ariaLabel: string
|
|
60
|
+
data: readonly T[]
|
|
61
|
+
x: (d: T) => X
|
|
62
|
+
xTicks?: number | readonly X[]
|
|
63
|
+
formatX?: ((x: X) => string)
|
|
64
|
+
legend?: false | ChartLegendConfig
|
|
65
|
+
height?: number | ResponsiveChartHeight
|
|
66
|
+
state?: ChartState
|
|
67
|
+
cursorGroup?: string
|
|
68
|
+
cursorResolution?: CursorResolution
|
|
69
|
+
tooltip?: false | ChartTooltipConfig<T, X>
|
|
70
|
+
states: readonly BandStripSeries<T>[]
|
|
71
|
+
getBand: (d: T) => BandSpan
|
|
72
|
+
fold?: BandFold<T>
|
|
57
73
|
Signature: Bars(props: BarsProps<T, X>): ReactElement<unknown, string | JSXElementConstructor<any>>
|
|
74
|
+
className?: string
|
|
75
|
+
style?: CSSProperties
|
|
76
|
+
ariaLabel: string
|
|
77
|
+
data: readonly T[]
|
|
78
|
+
x: (d: T) => X
|
|
79
|
+
y?: AxisConfig<T>
|
|
80
|
+
y2?: AxisConfig<T>
|
|
81
|
+
xTicks?: number | readonly X[]
|
|
82
|
+
formatX?: ((x: X) => string)
|
|
83
|
+
zones?: readonly ZoneSpec[]
|
|
84
|
+
xZones?: readonly XZoneSpec<X>[]
|
|
85
|
+
refLines?: readonly RefLine[]
|
|
86
|
+
legend?: false | ChartLegendConfig
|
|
87
|
+
height?: number | ResponsiveChartHeight
|
|
88
|
+
state?: ChartState
|
|
89
|
+
cursorGroup?: string
|
|
90
|
+
cursorResolution?: CursorResolution
|
|
91
|
+
tooltip?: false | ChartTooltipConfig<T, X>
|
|
92
|
+
bars: readonly BarsBar<T>[]
|
|
93
|
+
lines?: readonly BarsLine<T>[]
|
|
94
|
+
layout?: "stacked" | "grouped" | "normalized"
|
|
95
|
+
barOpacity?: ((d: T, key: string) => number)
|
|
58
96
|
Signature: CartesianChart(props: CartesianChartProps<T, X>): ReactElement<unknown, string | JSXElementConstructor<any>>
|
|
97
|
+
className?: string
|
|
98
|
+
style?: CSSProperties
|
|
99
|
+
ariaLabel: string
|
|
100
|
+
data: readonly T[]
|
|
101
|
+
x: (d: T) => X
|
|
102
|
+
series: readonly ChartSeries<T>[]
|
|
103
|
+
marks: (plot: PlotContext<T, X>) => ChartMarks
|
|
104
|
+
y?: AxisConfig<T>
|
|
105
|
+
y2?: AxisConfig<T>
|
|
106
|
+
xTicks?: number | readonly X[]
|
|
107
|
+
formatX?: ((x: X) => string)
|
|
108
|
+
zones?: readonly ZoneSpec[]
|
|
109
|
+
xZones?: readonly XZoneSpec<X>[]
|
|
110
|
+
refLines?: readonly RefLine[]
|
|
111
|
+
legend?: false | ChartLegendConfig
|
|
112
|
+
height?: number | ResponsiveChartHeight
|
|
113
|
+
state?: ChartState
|
|
114
|
+
cursorGroup?: string
|
|
115
|
+
cursorResolution?: CursorResolution
|
|
116
|
+
tooltip?: false | ChartTooltipConfig<T, X>
|
|
59
117
|
Signature: ChartCard(props: ChartCardProps): ReactElement<unknown, string | JSXElementConstructor<any>>
|
|
118
|
+
className?: string
|
|
119
|
+
style?: CSSProperties
|
|
120
|
+
classNames?: Partial<Record<ChartCardSlot, string>>
|
|
121
|
+
title?: string
|
|
122
|
+
icon?: ReactNode
|
|
123
|
+
subtitle?: string
|
|
124
|
+
info?: string
|
|
125
|
+
value?: string
|
|
126
|
+
delta?: number
|
|
127
|
+
deltaPeriod?: string
|
|
128
|
+
deltaPolarity?: DeltaPolarity
|
|
129
|
+
count?: number
|
|
130
|
+
actions?: ReactNode
|
|
131
|
+
state?: ChartState
|
|
132
|
+
placeholderHeight?: number | ResponsiveChartHeight
|
|
133
|
+
stateAction?: ReactNode
|
|
134
|
+
children?: ReactNode
|
|
60
135
|
Signature: Donut(props: DonutProps<K>): ReactElement<unknown, string | JSXElementConstructor<any>>
|
|
136
|
+
className?: string
|
|
137
|
+
style?: CSSProperties
|
|
138
|
+
ariaLabel: string
|
|
139
|
+
data: readonly DonutDatum<K>[]
|
|
140
|
+
colorForKey: (key: K) => string
|
|
141
|
+
formatValue: (v: number) => string
|
|
142
|
+
seriesLabel?: ((key: K) => string)
|
|
143
|
+
centerLabel?: string
|
|
144
|
+
centerSubLabel?: string
|
|
145
|
+
height?: number | ResponsiveChartHeight
|
|
146
|
+
state?: ChartState
|
|
61
147
|
Signature: DualPanel(props: DualPanelProps<T, X>): ReactElement<unknown, string | JSXElementConstructor<any>>
|
|
148
|
+
className?: string
|
|
149
|
+
style?: CSSProperties
|
|
150
|
+
ariaLabel: string
|
|
151
|
+
data: readonly T[]
|
|
152
|
+
x: (d: T) => X
|
|
153
|
+
formatX?: ((x: X) => string)
|
|
154
|
+
legend?: false | ChartLegendConfig
|
|
155
|
+
height?: number | ResponsiveChartHeight
|
|
156
|
+
state?: ChartState
|
|
157
|
+
cursorGroup?: string
|
|
158
|
+
cursorResolution?: CursorResolution
|
|
159
|
+
tooltip?: false | ChartTooltipConfig<T, X>
|
|
160
|
+
series: readonly DualPanelLine<T>[]
|
|
161
|
+
top?: { domain?: readonly [number, number] | "auto" | undefined; …
|
|
162
|
+
fillBetween?: { from: string; to: string; fill: string; aboveFill?: strin…
|
|
163
|
+
bar: DualPanelBar<T>
|
|
164
|
+
topFraction?: number
|
|
62
165
|
Signature: Heatmap(props: HeatmapProps<T>): ReactElement<unknown, string | JSXElementConstructor<any>>
|
|
166
|
+
className?: string
|
|
167
|
+
style?: CSSProperties
|
|
168
|
+
ariaLabel: string
|
|
169
|
+
data: readonly T[]
|
|
170
|
+
getRow: (d: T) => string
|
|
171
|
+
getCol: (d: T) => string
|
|
172
|
+
getValue: (d: T) => number | null
|
|
173
|
+
rows?: readonly string[]
|
|
174
|
+
cols?: readonly string[]
|
|
175
|
+
color?: string
|
|
176
|
+
domain?: readonly [number, number]
|
|
177
|
+
formatValue?: ((v: number) => string)
|
|
178
|
+
formatRow?: ((row: string) => string)
|
|
179
|
+
formatCol?: ((col: string) => string)
|
|
180
|
+
legend?: false | { label?: string | undefined; }
|
|
181
|
+
tooltip?: false | { rows?: ((d: T) => readonly ChartTooltipRow[]) | u…
|
|
182
|
+
height?: number | ResponsiveChartHeight
|
|
183
|
+
matchHeight?: boolean
|
|
184
|
+
state?: ChartState
|
|
63
185
|
Signature: Lines(props: LinesProps<T, X>): ReactElement<unknown, string | JSXElementConstructor<any>>
|
|
186
|
+
className?: string
|
|
187
|
+
style?: CSSProperties
|
|
188
|
+
ariaLabel: string
|
|
189
|
+
data: readonly T[]
|
|
190
|
+
x: (d: T) => X
|
|
191
|
+
series: readonly ChartSeries<T>[]
|
|
192
|
+
y?: AxisConfig<T>
|
|
193
|
+
y2?: AxisConfig<T>
|
|
194
|
+
xTicks?: number | readonly X[]
|
|
195
|
+
formatX?: ((x: X) => string)
|
|
196
|
+
zones?: readonly ZoneSpec[]
|
|
197
|
+
xZones?: readonly XZoneSpec<X>[]
|
|
198
|
+
refLines?: readonly RefLine[]
|
|
199
|
+
legend?: false | ChartLegendConfig
|
|
200
|
+
height?: number | ResponsiveChartHeight
|
|
201
|
+
state?: ChartState
|
|
202
|
+
cursorGroup?: string
|
|
203
|
+
cursorResolution?: CursorResolution
|
|
204
|
+
tooltip?: false | ChartTooltipConfig<T, X>
|
|
205
|
+
thresholds?: [X] extends [string] ? never : readonly Threshold[]
|
|
64
206
|
Signature: MirroredBars(props: MirroredBarsProps<T, X>): ReactElement<unknown, string | JSXElementConstructor<any>>
|
|
207
|
+
className?: string
|
|
208
|
+
style?: CSSProperties
|
|
209
|
+
ariaLabel: string
|
|
210
|
+
data: readonly T[]
|
|
211
|
+
x: (d: T) => X
|
|
212
|
+
formatX?: ((x: X) => string)
|
|
213
|
+
legend?: false | ChartLegendConfig
|
|
214
|
+
height?: number | ResponsiveChartHeight
|
|
215
|
+
state?: ChartState
|
|
216
|
+
cursorGroup?: string
|
|
217
|
+
tooltip?: false | ChartTooltipConfig<T, X>
|
|
218
|
+
series: readonly MirroredBarsSeries<T>[]
|
|
219
|
+
up: MirroredBarPane
|
|
220
|
+
down: MirroredBarPane
|
|
221
|
+
upFraction?: number
|
|
222
|
+
getAbsentFraction?: ((d: T) => number)
|
|
223
|
+
getBarOpacity?: ((d: T) => number)
|
|
224
|
+
fold?: { minBandPx?: number | undefined; merge: (group: T[]) => T;…
|
|
225
|
+
cursorResolution?: CursorResolution
|
|
65
226
|
Signature: Sparkline(props: SparklineProps): ReactElement<unknown, string | JSXElementConstructor<any>>
|
|
227
|
+
className?: string
|
|
228
|
+
style?: CSSProperties
|
|
229
|
+
ariaLabel: string
|
|
230
|
+
data: readonly number[]
|
|
231
|
+
height: number
|
|
232
|
+
width?: number
|
|
233
|
+
mark?: "line" | "bar"
|
|
234
|
+
color?: string
|
|
235
|
+
emphasizeLast?: boolean
|
|
236
|
+
emphasisColor?: string
|
|
237
|
+
state?: ChartState
|
|
66
238
|
Signature: StackedArea(props: StackedAreaProps<T, X>): ReactElement<unknown, string | JSXElementConstructor<any>>
|
|
239
|
+
className?: string
|
|
240
|
+
style?: CSSProperties
|
|
241
|
+
ariaLabel: string
|
|
242
|
+
data: readonly T[]
|
|
243
|
+
x: (d: T) => X
|
|
244
|
+
xTicks?: number | readonly X[]
|
|
245
|
+
formatX?: ((x: X) => string)
|
|
246
|
+
zones?: readonly ZoneSpec[]
|
|
247
|
+
xZones?: readonly XZoneSpec<X>[]
|
|
248
|
+
refLines?: readonly RefLine[]
|
|
249
|
+
legend?: false | ChartLegendConfig
|
|
250
|
+
height?: number | ResponsiveChartHeight
|
|
251
|
+
state?: ChartState
|
|
252
|
+
cursorGroup?: string
|
|
253
|
+
cursorResolution?: CursorResolution
|
|
254
|
+
tooltip?: false | ChartTooltipConfig<T, X>
|
|
255
|
+
series: readonly StackedAreaBand<T>[]
|
|
256
|
+
y?: Omit<AxisConfig<T>, "scale">
|
|
67
257
|
Signature: chartCursor(group: string): ChartCursorController<ChartValue, ChartValue>
|
|
68
258
|
Signature: chartCurve(name: CurveName): ChartCurve
|
|
69
259
|
Install: bun add @tanstack/charts@1.1.0 d3-scale@4.0.2
|
|
@@ -113,8 +303,10 @@ Description: Mantine form layer: useBasaltForm + inputProps/fieldKey (two calls
|
|
|
113
303
|
Layer: mantine-coupled
|
|
114
304
|
Rule: basalt-batteries
|
|
115
305
|
Signature: fieldKey(form: UseFormReturnType<Values>, path: Path): string
|
|
116
|
-
Signature: inputProps(form: UseFormReturnType<Values>, path: Path):
|
|
306
|
+
Signature: inputProps(form: UseFormReturnType<Values>, path: Path): InputProps
|
|
117
307
|
Signature: useBasaltForm(opts: UseBasaltFormOptions<Values>): UseFormReturnType<Values>
|
|
308
|
+
mode?: "controlled" | "uncontrolled"
|
|
309
|
+
schema?: StandardSchemaV1<unknown, Values>
|
|
118
310
|
Install: bun add @mantine/form@^9.7.0
|
|
119
311
|
|
|
120
312
|
## basalt-ui/commands
|
|
@@ -139,6 +331,47 @@ Description: BasaltDataTable and createColumnHelper: a data table over TanStack
|
|
|
139
331
|
Layer: mantine-coupled
|
|
140
332
|
Rule: basalt-batteries
|
|
141
333
|
Signature: BasaltDataTable(props: BasaltDataTableProps<T>): JSX.Element
|
|
334
|
+
className?: string
|
|
335
|
+
style?: CSSProperties
|
|
336
|
+
classNames?: Partial<Record<BasaltDataTableSlot, string>>
|
|
337
|
+
title?: string
|
|
338
|
+
icon?: ReactNode
|
|
339
|
+
subtitle?: string
|
|
340
|
+
data: T[]
|
|
341
|
+
columns: BasaltColumnDef<T>[]
|
|
342
|
+
enableSorting?: boolean
|
|
343
|
+
manualSorting?: boolean
|
|
344
|
+
striped?: boolean | "odd" | "even"
|
|
345
|
+
highlightOnHover?: boolean
|
|
346
|
+
emptyState?: ReactNode
|
|
347
|
+
isLoading?: boolean
|
|
348
|
+
query?: QueryStateLike<unknown>
|
|
349
|
+
skeletonRows?: number
|
|
350
|
+
initialSorting?: SortingState
|
|
351
|
+
onSortingChange?: (sorting: SortingState) => void
|
|
352
|
+
enableGlobalFilter?: boolean
|
|
353
|
+
globalFilterPlaceholder?: string
|
|
354
|
+
searchIcon?: ReactNode
|
|
355
|
+
initialGlobalFilter?: string
|
|
356
|
+
onGlobalFilterChange?: (value: string) => void
|
|
357
|
+
facets?: DataTableFacet<T>[]
|
|
358
|
+
onColumnFiltersChange?: (filters: ColumnFiltersState) => void
|
|
359
|
+
manualFiltering?: boolean
|
|
360
|
+
actions?: SlotActions
|
|
361
|
+
onRowActivate?: (row: T) => void
|
|
362
|
+
renderCard?: (row: T) => ReactNode
|
|
363
|
+
enableRowSelection?: boolean
|
|
364
|
+
rowSelection?: RowSelectionState
|
|
365
|
+
onRowSelectionChange?: (selection: RowSelectionState) => void
|
|
366
|
+
getRowId?: (row: T, index: number) => string
|
|
367
|
+
bulkActions?: (rows: T[]) => BarAction[]
|
|
368
|
+
rowActions?: DataTableRowAction<T>[]
|
|
369
|
+
rowLabel?: (row: T) => string
|
|
370
|
+
enablePagination?: boolean
|
|
371
|
+
pageSizeOptions?: number[]
|
|
372
|
+
initialPagination?: PaginationState
|
|
373
|
+
onPaginationChange?: (pagination: PaginationState) => void
|
|
374
|
+
… +13 more
|
|
142
375
|
Signature: createColumnHelper(): ColumnHelper<{ rowSortingFeature: TableFeature; columnFilteringFeatur…
|
|
143
376
|
Install: bun add @tanstack/react-table@9.2.8
|
|
144
377
|
|
|
@@ -176,7 +409,7 @@ OptionalPeers: shiki@^4.5.0, @shikijs/langs@^4.5.0, @shikijs/themes@^4.5.0, beau
|
|
|
176
409
|
|
|
177
410
|
## basalt-ui/controls
|
|
178
411
|
Import: import { ... } from 'basalt-ui/controls'
|
|
179
|
-
Description: The control tier (docs/CONTROLS-SPEC.md §3): FilterSet (nowrap row + measured +N fold + the mobile Filters (n) sheet), RangeFilter
|
|
412
|
+
Description: The control tier (docs/CONTROLS-SPEC.md §3). Exports: `FilterSet` (nowrap row + measured +N fold + the mobile Filters (n) sheet), `RangeFilter`/`SelectFilter`/`MultiSelectFilter`/`NumberFilter`/`SearchFilter`/`ToggleFilter` (each bound to a FieldHandle — no value/onChange/size, law C2/C5; `NumberFilter` is the field.number lane, a radio list over `options` or a stepper without), `ViewTabs`, `SyncButton` with the `BarAction`/`GlobalAction` types, and the form layout `FormRow`/`FormGroup` (moved here from ./forms in 1.36.0 — `FormRow` is law C1’s form row and needs no @mantine/form). THREE surfaces, picked by the home and never by a prop: pill in a PageBar row, sheet in the mobile Filters (n) drawer, panel in a PageAside body — where every control renders an inspector/facet ROW instead of a chip (docs/ASIDE-SPEC.md §3); the counts/max props on `MultiSelectFilter` render the Foundry facet list there. Every control owns its own desktop/mobile swap in CSS (C9) and renders size="ctl" internally. Resolves and renders with NO @mantine/dates installed — the custom date picker is injected through RangeFilter.customPicker from ./controls-dates.
|
|
180
413
|
Layer: mantine-coupled
|
|
181
414
|
Rule: basalt-controls
|
|
182
415
|
Signature: FilterSet(props: FilterSetProps): ReactNode
|
package/package.json
CHANGED
|
@@ -137,9 +137,10 @@ export type FormRowProps = BasaltProps &
|
|
|
137
137
|
hint?: string
|
|
138
138
|
/**
|
|
139
139
|
* The field's error, rendered under the control. Falsy renders nothing. For a Mantine input
|
|
140
|
-
* wired through `inputProps(form, path)`, Mantine's own `Input.Wrapper` already renders
|
|
141
|
-
*
|
|
142
|
-
*
|
|
140
|
+
* wired through `inputProps(form, path)`, Mantine's own `Input.Wrapper` already renders the
|
|
141
|
+
* field error — passing it here too would render it twice. Reserve this prop for children that
|
|
142
|
+
* render no error of their own (a raw input, a custom control) and read it typed:
|
|
143
|
+
* `error={inputProps(form, path).error}`.
|
|
143
144
|
*/
|
|
144
145
|
error?: ReactNode
|
|
145
146
|
/** Marks the field required: an accent `*` for sighted readers, `(required)` for assistive tech. */
|
|
@@ -172,7 +173,7 @@ export type FormRowProps = BasaltProps &
|
|
|
172
173
|
*
|
|
173
174
|
* @example
|
|
174
175
|
* // A raw control renders no error of its own — pass it explicitly.
|
|
175
|
-
* <FormRow label="Email" required error={form
|
|
176
|
+
* <FormRow label="Email" required error={inputProps(form, 'email').error}>
|
|
176
177
|
* <input value={form.values.email} onChange={(e) => form.setFieldValue('email', e.target.value)} />
|
|
177
178
|
* </FormRow>
|
|
178
179
|
*/
|
|
@@ -239,8 +240,16 @@ export type FormGroupProps = BasaltProps & {
|
|
|
239
240
|
*
|
|
240
241
|
* @example
|
|
241
242
|
* <FormGroup label="Notify me about" direction="row">
|
|
242
|
-
* <Checkbox
|
|
243
|
-
*
|
|
243
|
+
* <Checkbox
|
|
244
|
+
* key={fieldKey(form, 'onDeploy')}
|
|
245
|
+
* {...inputProps(form, 'onDeploy', { type: 'checkbox' })}
|
|
246
|
+
* label="Deploys"
|
|
247
|
+
* />
|
|
248
|
+
* <Switch
|
|
249
|
+
* key={fieldKey(form, 'onError')}
|
|
250
|
+
* {...inputProps(form, 'onError', { type: 'checkbox' })}
|
|
251
|
+
* label="Errors"
|
|
252
|
+
* />
|
|
244
253
|
* </FormGroup>
|
|
245
254
|
*/
|
|
246
255
|
export function FormGroup(props: FormGroupProps) {
|