@coldsmirk/ledger-mantine 0.4.0 → 0.5.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/dist/index.cjs CHANGED
@@ -1087,6 +1087,10 @@ function resolveIcons(icons) {
1087
1087
  const defaultLabels = {
1088
1088
  paginationSummary: (from, to, total) => `${from}–${to} of ${total}`,
1089
1089
  rowsPerPage: "Rows per page",
1090
+ firstPage: "First page",
1091
+ previousPage: "Previous page",
1092
+ nextPage: "Next page",
1093
+ lastPage: "Last page",
1090
1094
  selectAllRows: "Select all rows",
1091
1095
  selectRow: "Select row",
1092
1096
  selectedCount: (count) => `${count} selected`,
@@ -1115,6 +1119,12 @@ const defaultLabels = {
1115
1119
  filterPlaceholder: "Filter…",
1116
1120
  filterRangeMin: "Min",
1117
1121
  filterRangeMax: "Max",
1122
+ previousMonth: "Previous month",
1123
+ nextMonth: "Next month",
1124
+ previousYear: "Previous year",
1125
+ nextYear: "Next year",
1126
+ previousDecade: "Previous decade",
1127
+ nextDecade: "Next decade",
1118
1128
  searchPlaceholder: "Search…",
1119
1129
  loading: "Loading",
1120
1130
  empty: "No data",
@@ -1600,6 +1610,12 @@ const DEFAULT_PAGE_SIZE_OPTIONS = [
1600
1610
  50,
1601
1611
  100
1602
1612
  ];
1613
+ const CONTROL_LABELS = {
1614
+ first: "firstPage",
1615
+ previous: "previousPage",
1616
+ next: "nextPage",
1617
+ last: "lastPage"
1618
+ };
1603
1619
  function PaginationBarCore({ table, labels, pageSizeOptions, size, className, style }) {
1604
1620
  const pageSizeLabelId = (0, react.useId)();
1605
1621
  const { pageIndex, pageSize } = table.atoms.pagination.get();
@@ -1615,7 +1631,7 @@ function PaginationBarCore({ table, labels, pageSizeOptions, size, className, st
1615
1631
  style,
1616
1632
  wrap: "wrap",
1617
1633
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1618
- c: "dimmed",
1634
+ c: "var(--ledger-color-dimmed)",
1619
1635
  size,
1620
1636
  children: labels.paginationSummary(from, to, total)
1621
1637
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Group, {
@@ -1625,7 +1641,7 @@ function PaginationBarCore({ table, labels, pageSizeOptions, size, className, st
1625
1641
  gap: "xs",
1626
1642
  wrap: "nowrap",
1627
1643
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Text, {
1628
- c: "dimmed",
1644
+ c: "var(--ledger-color-dimmed)",
1629
1645
  id: pageSizeLabelId,
1630
1646
  size,
1631
1647
  children: labels.rowsPerPage
@@ -1639,6 +1655,9 @@ function PaginationBarCore({ table, labels, pageSizeOptions, size, className, st
1639
1655
  onChange: (value) => value !== null && table.setPageSize(Number(value))
1640
1656
  })]
1641
1657
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Pagination, {
1658
+ getControlProps: (control) => {
1659
+ return { "aria-label": labels[CONTROL_LABELS[control]] };
1660
+ },
1642
1661
  size: SIZES[size].control,
1643
1662
  total: pageCount,
1644
1663
  value: pageIndex + 1,
@@ -3060,6 +3079,14 @@ function autosizeColumn(setColumnSizing, { columnId, minSize, maxSize, hasFilter
3060
3079
  * a black box that may ship no clear of its own — keeps the popover-level fallback.
3061
3080
  */
3062
3081
  const FACETED_OPTIONS_CAP = 100;
3082
+ /**
3083
+ * The smallest pointer target WCAG 2.2 AA accepts without spacing around it, in px.
3084
+ */
3085
+ const MIN_TARGET_SIZE = 24;
3086
+ /**
3087
+ * The calendar's weekend color, as the variable Mantine's day rule reads (see DateRangeFilter).
3088
+ */
3089
+ const WEEKEND_COLOR = { "--mantine-color-red-6": "color-mix(in srgb, var(--mantine-color-red-text), var(--mantine-color-text) 30%)" };
3063
3090
  function FilterPopover({ column }) {
3064
3091
  const { labels, icons, getStyles, filterMode, size } = useDataTableContext();
3065
3092
  const filter = column.columnDef.meta?.filter;
@@ -3073,6 +3100,8 @@ function FilterPopover({ column }) {
3073
3100
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Popover.Target, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.ActionIcon, {
3074
3101
  "aria-label": name,
3075
3102
  "data-active": active || void 0,
3103
+ mih: MIN_TARGET_SIZE,
3104
+ miw: MIN_TARGET_SIZE,
3076
3105
  size: SIZES[size].control,
3077
3106
  variant: active ? "light" : "subtle",
3078
3107
  onClick: (event) => event.stopPropagation(),
@@ -3254,11 +3283,21 @@ function DateRangeFilter({ column, name }) {
3254
3283
  const filterValue = column.getFilterValue();
3255
3284
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_dates.DatePicker, {
3256
3285
  allowSingleDateInRange: true,
3286
+ hideOutsideDates: true,
3257
3287
  highlightToday: true,
3258
3288
  "aria-label": name,
3259
3289
  size: "xs",
3290
+ style: WEEKEND_COLOR,
3260
3291
  type: "range",
3261
3292
  value: filterValue ?? [null, null],
3293
+ ariaLabels: {
3294
+ previousMonth: labels.previousMonth,
3295
+ nextMonth: labels.nextMonth,
3296
+ previousYear: labels.previousYear,
3297
+ nextYear: labels.nextYear,
3298
+ previousDecade: labels.previousDecade,
3299
+ nextDecade: labels.nextDecade
3300
+ },
3262
3301
  onChange: (next) => column.setFilterValue(!next[0] && !next[1] ? void 0 : next)
3263
3302
  }), filterValue !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Group, {
3264
3303
  justify: "flex-end",
@@ -3836,6 +3875,24 @@ const builtInFilterFns = {
3836
3875
  startsWith: _tanstack_react_table.filterFn_startsWith,
3837
3876
  weakEquals: _tanstack_react_table.filterFn_weakEquals
3838
3877
  };
3878
+ /**
3879
+ * Typed through the exported definitions on purpose: since 9.2 several of their value types
3880
+ * name an alias TanStack does not export, and an inferred registry would carry that alias into
3881
+ * ledger's declaration files, where no consumer can resolve it.
3882
+ */
3883
+ const builtInAggregationFns = {
3884
+ count: _tanstack_react_table.aggregationFn_count,
3885
+ extent: _tanstack_react_table.aggregationFn_extent,
3886
+ first: _tanstack_react_table.aggregationFn_first,
3887
+ last: _tanstack_react_table.aggregationFn_last,
3888
+ max: _tanstack_react_table.aggregationFn_max,
3889
+ mean: _tanstack_react_table.aggregationFn_mean,
3890
+ median: _tanstack_react_table.aggregationFn_median,
3891
+ min: _tanstack_react_table.aggregationFn_min,
3892
+ sum: _tanstack_react_table.aggregationFn_sum,
3893
+ unique: _tanstack_react_table.aggregationFn_unique,
3894
+ uniqueCount: _tanstack_react_table.aggregationFn_uniqueCount
3895
+ };
3839
3896
  const ledgerFeatures = (0, _tanstack_react_table.tableFeatures)({
3840
3897
  cellSpanningFeature: _tanstack_react_table.cellSpanningFeature,
3841
3898
  columnFacetingFeature: _tanstack_react_table.columnFacetingFeature,
@@ -3860,19 +3917,7 @@ const ledgerFeatures = (0, _tanstack_react_table.tableFeatures)({
3860
3917
  groupedRowModel: (0, _tanstack_react_table.createGroupedRowModel)(),
3861
3918
  paginatedRowModel: (0, _tanstack_react_table.createPaginatedRowModel)(),
3862
3919
  sortedRowModel: (0, _tanstack_react_table.createSortedRowModel)(),
3863
- aggregationFns: {
3864
- count: _tanstack_react_table.aggregationFn_count,
3865
- extent: _tanstack_react_table.aggregationFn_extent,
3866
- first: _tanstack_react_table.aggregationFn_first,
3867
- last: _tanstack_react_table.aggregationFn_last,
3868
- max: _tanstack_react_table.aggregationFn_max,
3869
- mean: _tanstack_react_table.aggregationFn_mean,
3870
- median: _tanstack_react_table.aggregationFn_median,
3871
- min: _tanstack_react_table.aggregationFn_min,
3872
- sum: _tanstack_react_table.aggregationFn_sum,
3873
- unique: _tanstack_react_table.aggregationFn_unique,
3874
- uniqueCount: _tanstack_react_table.aggregationFn_uniqueCount
3875
- },
3920
+ aggregationFns: builtInAggregationFns,
3876
3921
  filterFns: {
3877
3922
  ...builtInFilterFns,
3878
3923
  ...ledgerFilterFns
@@ -6393,6 +6438,33 @@ function useStylesRevision(getStyles, selectors) {
6393
6438
  return revision;
6394
6439
  }
6395
6440
  //#endregion
6441
+ //#region src/use-viewport-overflow.ts
6442
+ /**
6443
+ * Whether the body viewport scrolls on either axis. A scroll container has to be reachable by
6444
+ * keyboard to be scrolled by it (WCAG 2.1.1), while a focus stop over content that fits is a
6445
+ * Tab press spent on nothing — so the viewport's focus stop follows this.
6446
+ *
6447
+ * Measured whenever the viewport or its content resizes: rows arriving, columns widening, or
6448
+ * the host resizing the table each change the answer without a scroll event. A 1px tolerance
6449
+ * absorbs fractional layout rounding, which would otherwise flicker the stop on and off.
6450
+ */
6451
+ function useViewportOverflow(viewport) {
6452
+ const [overflowing, setOverflowing] = (0, react.useState)(false);
6453
+ (0, react.useLayoutEffect)(() => {
6454
+ if (!viewport) return;
6455
+ const measure = () => {
6456
+ const next = viewport.scrollHeight - viewport.clientHeight > 1 || viewport.scrollWidth - viewport.clientWidth > 1;
6457
+ setOverflowing(next);
6458
+ };
6459
+ measure();
6460
+ const observer = new ResizeObserver(measure);
6461
+ observer.observe(viewport);
6462
+ if (viewport.firstElementChild) observer.observe(viewport.firstElementChild);
6463
+ return () => observer.disconnect();
6464
+ }, [viewport]);
6465
+ return overflowing;
6466
+ }
6467
+ //#endregion
6396
6468
  //#region src/data-table.tsx
6397
6469
  /**
6398
6470
  * The root component (docs/api.md): a generic Mantine factory with full Styles API,
@@ -6450,7 +6522,7 @@ const STYLE_SELECTORS = Object.keys(classes);
6450
6522
  */
6451
6523
  const NO_ARIA_ROWS = [];
6452
6524
  const EMPTY_STATE_STYLES = { title: {
6453
- color: "var(--mantine-color-dimmed)",
6525
+ color: "var(--ledger-color-dimmed)",
6454
6526
  fontWeight: 500
6455
6527
  } };
6456
6528
  const defaultProps = {
@@ -6642,6 +6714,7 @@ function DataTableCore({ presentation, stylesProps, table }) {
6642
6714
  viewportRef.current = element;
6643
6715
  setViewport(element);
6644
6716
  }, []);
6717
+ const viewportOverflows = useViewportOverflow(viewport);
6645
6718
  const startLeafColumns = table.getStartVisibleLeafColumns();
6646
6719
  const endLeafColumns = table.getEndVisibleLeafColumns();
6647
6720
  const displayColumns = [
@@ -6857,7 +6930,7 @@ function DataTableCore({ presentation, stylesProps, table }) {
6857
6930
  rowPinningActive,
6858
6931
  withDetailPanels
6859
6932
  ]);
6860
- const bodyAriaRowCount = loading && logicalDisplayRowCount === 0 ? skeletonRowCount : logicalDisplayRowCount + (loadMoreError || loadingMore ? 1 : 0);
6933
+ const bodyAriaRowCount = loading && logicalDisplayRowCount === 0 ? skeletonRowCount : logicalDisplayRowCount + (loadMoreError || loadingMore ? 1 : 0) + (isEmpty || errorActive ? 1 : 0);
6861
6934
  const footerRowCount = visibleFooterGroups(table).length;
6862
6935
  const ariaRowCount = headerRowCount + bodyAriaRowCount + footerRowCount;
6863
6936
  const footerAriaRowIndexStart = headerRowCount + bodyAriaRowCount + 1;
@@ -7231,11 +7304,10 @@ function DataTableCore({ presentation, stylesProps, table }) {
7231
7304
  },
7232
7305
  viewportProps: mergeElementProps(viewportProps, {
7233
7306
  style: { overscrollBehavior: "none" },
7307
+ role: "rowgroup",
7234
7308
  "aria-describedby": viewportDescribedBy,
7235
- ...activeRowEnabled && {
7236
- tabIndex: 0,
7237
- onKeyDown: handleActiveRowKeyDown
7238
- }
7309
+ tabIndex: activeRowEnabled || viewportOverflows ? 0 : void 0,
7310
+ ...activeRowEnabled && { onKeyDown: handleActiveRowKeyDown }
7239
7311
  }),
7240
7312
  onScrollPositionChange: handleScrollPositionChange,
7241
7313
  children: [
@@ -7258,43 +7330,59 @@ function DataTableCore({ presentation, stylesProps, table }) {
7258
7330
  })]
7259
7331
  }),
7260
7332
  isEmpty && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7261
- ...getStyles("empty"),
7262
- "data-variant": filtersActive ? "no-results" : "no-data",
7263
- role: "status",
7264
- children: emptyState ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.EmptyState, {
7265
- withIndicatorBackground: true,
7266
- size: "sm",
7267
- styles: EMPTY_STATE_STYLES,
7268
- title: filtersActive ? labels.noResults : labels.empty,
7269
- icon: filtersActive ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(icons.noResults, {
7270
- size: 40,
7271
- strokeWidth: 1.5
7272
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(icons.empty, {
7273
- size: 40,
7274
- strokeWidth: 1.5
7333
+ "aria-rowindex": virtualEnabled ? headerRowCount + bodyAriaRowCount : void 0,
7334
+ role: "row",
7335
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7336
+ ...getStyles("empty"),
7337
+ "aria-colspan": visibleLeafColumns.length,
7338
+ "data-variant": filtersActive ? "no-results" : "no-data",
7339
+ role: "cell",
7340
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7341
+ role: "status",
7342
+ children: emptyState ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.EmptyState, {
7343
+ withIndicatorBackground: true,
7344
+ size: "sm",
7345
+ styles: EMPTY_STATE_STYLES,
7346
+ title: filtersActive ? labels.noResults : labels.empty,
7347
+ icon: filtersActive ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(icons.noResults, {
7348
+ size: 40,
7349
+ strokeWidth: 1.5
7350
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(icons.empty, {
7351
+ size: 40,
7352
+ strokeWidth: 1.5
7353
+ })
7354
+ })
7275
7355
  })
7276
7356
  })
7277
7357
  }),
7278
7358
  errorActive && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7279
- ...getStyles("empty"),
7280
- "data-over-rows": rowsLength > 0 || void 0,
7281
- "data-variant": "error",
7282
- role: "alert",
7283
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.EmptyState, {
7284
- withIndicatorBackground: true,
7285
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(icons.error, {
7286
- size: 40,
7287
- strokeWidth: 1.5
7288
- }),
7289
- size: "sm",
7290
- styles: EMPTY_STATE_STYLES,
7291
- title: error === true ? labels.error : error,
7292
- children: onRetry && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
7293
- leftSection: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(icons.retry, { size: 14 }),
7294
- size: "xs",
7295
- variant: "light",
7296
- onClick: onRetry,
7297
- children: labels.retry
7359
+ "aria-rowindex": virtualEnabled ? headerRowCount + bodyAriaRowCount : void 0,
7360
+ role: "row",
7361
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7362
+ ...getStyles("empty"),
7363
+ "aria-colspan": visibleLeafColumns.length,
7364
+ "data-over-rows": rowsLength > 0 || void 0,
7365
+ "data-variant": "error",
7366
+ role: "cell",
7367
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7368
+ role: "alert",
7369
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.EmptyState, {
7370
+ withIndicatorBackground: true,
7371
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(icons.error, {
7372
+ size: 40,
7373
+ strokeWidth: 1.5
7374
+ }),
7375
+ size: "sm",
7376
+ styles: EMPTY_STATE_STYLES,
7377
+ title: error === true ? labels.error : error,
7378
+ children: onRetry && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.Button, {
7379
+ leftSection: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(icons.retry, { size: 14 }),
7380
+ size: "xs",
7381
+ variant: "light",
7382
+ onClick: onRetry,
7383
+ children: labels.retry
7384
+ })
7385
+ })
7298
7386
  })
7299
7387
  })
7300
7388
  })