@coldsmirk/ledger-mantine 0.1.0 → 0.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Venus
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,15 +1,22 @@
1
1
  # @coldsmirk/ledger-mantine
2
2
 
3
- A Mantine-native `<DataTable>` built on [TanStack Table](https://tanstack.com/table) and [TanStack Virtual](https://tanstack.com/virtual): sorting, filtering, pagination, row selection, column pinning/resizing/visibility, master–detail expansion, inline cell editing, and adaptive row virtualization — rendered as a real `<table>` with Mantine's table styling.
3
+ [![npm version](https://img.shields.io/npm/v/%40coldsmirk%2Fledger-mantine)](https://www.npmjs.com/package/@coldsmirk/ledger-mantine)
4
+ [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/coldsmirk/ledger/blob/main/LICENSE)
4
5
 
5
- > **Status: implemented and pre-release.** The component, documentation, tests, build, and package validation gates are in place. The package has not been published to npm yet.
6
+ A Mantine-native `<DataTable>` built on [TanStack Table](https://tanstack.com/table) and [TanStack Virtual](https://tanstack.com/virtual): sorting, filtering, pagination, row selection, column pinning/resizing/visibility, master–detail expansion, tree data, grouping, inline editing, row reordering, and row/column virtualization — rendered as a real `<table>` with Mantine's table styling.
6
7
 
7
- ## Install
8
+ **Live demo:** [coldsmirk.github.io/ledger](https://coldsmirk.github.io/ledger/) — one page per feature area, each with a view-source drawer.
9
+
10
+ > Pre-1.0: the public surface is complete and documented, but minor releases may still contain breaking changes while the API settles.
11
+
12
+ ## Installation
8
13
 
9
14
  ```bash
10
- pnpm add @coldsmirk/ledger-mantine @mantine/core @mantine/dates @mantine/hooks dayjs react react-dom
15
+ pnpm add @coldsmirk/ledger-mantine
11
16
  ```
12
17
 
18
+ Peer dependencies: `@mantine/core`, `@mantine/dates`, and `@mantine/hooks` `^9.0.0`; `react` and `react-dom` `^19.2.0`; and `dayjs` as required by `@mantine/dates`. `@tanstack/react-table` and `@tanstack/react-virtual` are direct dependencies — everything a table needs is re-exported from the main entry.
19
+
13
20
  Import Mantine's styles and ledger's layered stylesheet once at the application entry point:
14
21
 
15
22
  ```tsx
@@ -18,8 +25,6 @@ import "@mantine/dates/styles.css";
18
25
  import "@coldsmirk/ledger-mantine/styles.css";
19
26
  ```
20
27
 
21
- Peer dependencies: `@mantine/core`, `@mantine/dates`, and `@mantine/hooks` `^9`; `react` and `react-dom` `^19.2`; and `dayjs` as required by `@mantine/dates`.
22
-
23
28
  ## First table
24
29
 
25
30
  ```tsx
@@ -46,4 +51,13 @@ export function PeopleTable({ people }: { people: Person[] }) {
46
51
 
47
52
  The behavior layer speaks TanStack's language (raw `ColumnDef`, verbatim state shapes, `enable*` switches), while the presentation layer speaks Mantine's (forwarded `Table` style props, `BoxProps` sizing, Styles API).
48
53
 
49
- See the repository's [getting-started guide](https://github.com/coldsmirk/ledger/blob/main/docs/getting-started.md), [feature guides](https://github.com/coldsmirk/ledger/tree/main/docs), and [complete API reference](https://github.com/coldsmirk/ledger/blob/main/docs/api.md).
54
+ ## Documentation
55
+
56
+ - [Getting started](https://github.com/coldsmirk/ledger/blob/main/docs/getting-started.md) — install, first table, sugar vs hook mode, app-wide defaults
57
+ - [Feature guides](https://github.com/coldsmirk/ledger/tree/main/docs) — one authoritative guide per feature area
58
+ - [API reference](https://github.com/coldsmirk/ledger/blob/main/docs/api.md) — the complete public surface with defaults
59
+ - [Recipes](https://github.com/coldsmirk/ledger/blob/main/docs/recipes.md) — server tables, URL sync, CSV download, and more
60
+
61
+ ## License
62
+
63
+ [MIT](https://github.com/coldsmirk/ledger/blob/main/LICENSE)
package/dist/index.cjs CHANGED
@@ -147,9 +147,10 @@ const dateRange = (row, columnId, filterValue) => {
147
147
  };
148
148
  dateRange.autoRemove = (value) => !value || !value[0] && !value[1];
149
149
  /**
150
- * Strict set membership for the multi-select variant. TanStack's `arrIncludesSome` expects an
151
- * array row value and degrades to substring matching on scalars ("active" would match
152
- * "inactive") — the variant's semantics are exact membership for scalar and array cells.
150
+ * Strict set membership for the multi-select variant. No TanStack built-in covers both cell
151
+ * shapes exactly: `arrIncludesSome` rejects non-array row values outright, `arrHas` rejects
152
+ * array cells, and `arrIncludes` substring-matches strings ("active" would match "inactive") —
153
+ * the variant's semantics are exact membership for scalar and array cells.
153
154
  */
154
155
  const oneOf = (row, columnId, filterValue) => {
155
156
  const raw = row.getValue(columnId);
@@ -517,10 +518,12 @@ function RowReorderOverlay({ session }) {
517
518
  function RowDragCell({ row, table }) {
518
519
  const { labels, icons, rowReorderKeyboard } = useDataTableContext();
519
520
  const orderable = table.options.meta?.ledger?.rowOrdering.orderable === true;
521
+ const pinned = table.options.enableRowPinning === true && row.getIsPinned() !== false;
520
522
  const { ref, isDragSource } = (0, _dnd_kit_react.useDraggable)({
521
523
  id: row.id,
522
- disabled: !orderable
524
+ disabled: !orderable || pinned
523
525
  });
526
+ if (pinned) return null;
524
527
  const lifted = rowReorderKeyboard?.active(row.id) === true;
525
528
  const handleKeyDown = (event) => {
526
529
  const keyboard = rowReorderKeyboard;
@@ -2868,8 +2871,9 @@ function TableBody({ table, virtualization, columnWindow, viewportRef, loading,
2868
2871
  //#endregion
2869
2872
  //#region src/table-footer.tsx
2870
2873
  /**
2871
- * Column footers (totals row). Rendered only when at least one leaf column declares a `footer`;
2872
- * pinned columns keep their sticky offsets so the totals track their columns.
2874
+ * Column footers (totals row). Rendered only when at least one column — leaf or group —
2875
+ * declares a `footer`; pinned columns keep their sticky offsets so the totals track their
2876
+ * columns.
2873
2877
  */
2874
2878
  /**
2875
2879
  * The footer rows that actually render. `getFooterGroups()` mirrors *every* header level, so a
@@ -3724,10 +3728,14 @@ function useColumnWidths(table, columns, viewport, tableMinWidth) {
3724
3728
  * object so `typeof ledgerFeatures` (`LedgerFeatures`) can pre-bind the `TFeatures` generic of
3725
3729
  * every re-exported type — consumers keep writing v8-shaped `ColumnDef<TData>` code.
3726
3730
  *
3727
- * - Every stock feature is registered EXCEPT `columnResizingFeature`: ledger owns the resize
3728
- * interaction end to end (`use-column-resize.ts`), so TanStack's drag machinery — and with it
3729
- * the `columnResizing` state slice, `getIsResizing()`, and `getResizeHandler()` — is not
3730
- * registered at all. Feature-gated APIs cannot lie about a pipeline that never runs.
3731
+ * - Every stock feature is registered EXCEPT the two below.
3732
+ * - `columnResizingFeature`: ledger owns the resize interaction end to end
3733
+ * (`use-column-resize.ts`), so TanStack's drag machinery — and with it the `columnResizing`
3734
+ * state slice, `getIsResizing()`, and `getResizeHandler()` — is not registered at all.
3735
+ * Feature-gated APIs cannot lie about a pipeline that never runs.
3736
+ * - `cellSelectionFeature`: cell selection is deferred until its own design round
3737
+ * (docs/DESIGN.md), so the `cellSelection` state slice, `enableCellSelection`, and
3738
+ * `cell.getIsSelected()` are likewise absent by the same rule.
3731
3739
  * - Row model factories are registered statically; the `manualX` translations decide at runtime
3732
3740
  * whether a model actually processes rows (client mode) or passes through (server mode).
3733
3741
  * - Every built-in fn ships registered under its conventional name. v9 resolves string ids —
@@ -6053,6 +6061,18 @@ function useDataTable(options) {
6053
6061
  enableRowSelection,
6054
6062
  withExpander
6055
6063
  ]);
6064
+ const setPublicColumnPinning = (0, react.useCallback)((updater) => {
6065
+ setColumnPinning((old) => {
6066
+ const next = (0, _tanstack_react_table.functionalUpdate)(updater, old);
6067
+ const start = next.start.filter((id) => !isInternalColumn(id));
6068
+ const end = next.end.filter((id) => !isInternalColumn(id));
6069
+ if (start.length === next.start.length && end.length === next.end.length) return next;
6070
+ return start.length === old.start.length && end.length === old.end.length && start.every((id, index) => id === old.start[index]) && end.every((id, index) => id === old.end[index]) ? old : {
6071
+ end,
6072
+ start
6073
+ };
6074
+ });
6075
+ }, [setColumnPinning]);
6056
6076
  if (isDev && (enableRowSelection || withExpander) && !getRowId) warnOnce("missing-get-row-id", "Row selection/expansion is enabled without getRowId — index-based row ids corrupt state across refetches.");
6057
6077
  const churn = (0, react.useRef)({
6058
6078
  renders: 0,
@@ -6150,7 +6170,7 @@ function useDataTable(options) {
6150
6170
  onRowSelectionChange: setRowSelection,
6151
6171
  onExpandedChange: setExpanded,
6152
6172
  onColumnVisibilityChange: setColumnVisibility,
6153
- onColumnPinningChange: setColumnPinning,
6173
+ onColumnPinningChange: setPublicColumnPinning,
6154
6174
  onColumnOrderChange: setColumnOrder,
6155
6175
  onColumnSizingChange: setColumnSizing,
6156
6176
  onGroupingChange: setGrouping,
@@ -6385,11 +6405,12 @@ const defaultProps = {
6385
6405
  function leafCol(column) {
6386
6406
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("col", { style: { width: `var(${columnWidthVar(column.id)})` } }, column.id);
6387
6407
  }
6388
- const varsResolver = (0, _mantine_core.createVarsResolver)((theme, { stripedColor, highlightOnHoverColor, borderColor }) => {
6408
+ const varsResolver = (0, _mantine_core.createVarsResolver)((theme, { stripedColor, highlightOnHoverColor, borderColor, radius }) => {
6389
6409
  return { root: {
6390
6410
  "--ledger-striped-color": stripedColor ? (0, _mantine_core.getThemeColor)(stripedColor, theme) : void 0,
6391
6411
  "--ledger-hover-color": highlightOnHoverColor ? (0, _mantine_core.getThemeColor)(highlightOnHoverColor, theme) : void 0,
6392
- "--ledger-border-color": borderColor ? (0, _mantine_core.getThemeColor)(borderColor, theme) : void 0
6412
+ "--ledger-border-color": borderColor ? (0, _mantine_core.getThemeColor)(borderColor, theme) : void 0,
6413
+ "--ledger-radius": radius === void 0 ? void 0 : (0, _mantine_core.getRadius)(radius)
6393
6414
  } };
6394
6415
  });
6395
6416
  const OPTION_KEY_SET = /* @__PURE__ */ new Set([
@@ -6510,7 +6531,7 @@ function DataTableFromOptions({ props }) {
6510
6531
  });
6511
6532
  }
6512
6533
  function DataTableCore({ presentation, stylesProps, table }) {
6513
- const { striped, stripedColor: _stripedColor, highlightOnHover, highlightOnHoverColor: _highlightOnHoverColor, withTableBorder, withColumnBorders, withRowBorders, borderColor: _borderColor, verticalSpacing, horizontalSpacing, tabularNums, tableMinWidth, virtualizedRows, virtualizedColumns, onEndReached, endReachedOffset, loadingMore, loadMoreError, loading, emptyState, error, onRetry, withColumnHeaders, withPaginationBar, pageSizeOptions, onRowClick, onRowActivate, onRowDoubleClick, onRowContextMenu, rowProps, headerRowProps, footerRowProps, viewportProps, labels: labelsProp, icons: iconsProp, handleRef, ref: rootRef, classNames, styles, unstyled, vars, className, style, attributes, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, ...others } = presentation;
6534
+ const { striped, stripedColor: _stripedColor, highlightOnHover, highlightOnHoverColor: _highlightOnHoverColor, withTableBorder, withColumnBorders, withRowBorders, borderColor: _borderColor, radius: _radius, verticalSpacing, horizontalSpacing, tabularNums, tableMinWidth, virtualizedRows, virtualizedColumns, onEndReached, endReachedOffset, loadingMore, loadMoreError, loading, emptyState, error, onRetry, withColumnHeaders, withPaginationBar, pageSizeOptions, onRowClick, onRowActivate, onRowDoubleClick, onRowContextMenu, rowProps, headerRowProps, footerRowProps, viewportProps, labels: labelsProp, icons: iconsProp, handleRef, ref: rootRef, classNames, styles, unstyled, vars, className, style, attributes, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, ...others } = presentation;
6514
6535
  const getStyles = (0, _mantine_core.useStyles)({
6515
6536
  name: "DataTable",
6516
6537
  classes,