@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.js CHANGED
@@ -1063,6 +1063,10 @@ function resolveIcons(icons) {
1063
1063
  const defaultLabels = {
1064
1064
  paginationSummary: (from, to, total) => `${from}–${to} of ${total}`,
1065
1065
  rowsPerPage: "Rows per page",
1066
+ firstPage: "First page",
1067
+ previousPage: "Previous page",
1068
+ nextPage: "Next page",
1069
+ lastPage: "Last page",
1066
1070
  selectAllRows: "Select all rows",
1067
1071
  selectRow: "Select row",
1068
1072
  selectedCount: (count) => `${count} selected`,
@@ -1091,6 +1095,12 @@ const defaultLabels = {
1091
1095
  filterPlaceholder: "Filter…",
1092
1096
  filterRangeMin: "Min",
1093
1097
  filterRangeMax: "Max",
1098
+ previousMonth: "Previous month",
1099
+ nextMonth: "Next month",
1100
+ previousYear: "Previous year",
1101
+ nextYear: "Next year",
1102
+ previousDecade: "Previous decade",
1103
+ nextDecade: "Next decade",
1094
1104
  searchPlaceholder: "Search…",
1095
1105
  loading: "Loading",
1096
1106
  empty: "No data",
@@ -1576,6 +1586,12 @@ const DEFAULT_PAGE_SIZE_OPTIONS = [
1576
1586
  50,
1577
1587
  100
1578
1588
  ];
1589
+ const CONTROL_LABELS = {
1590
+ first: "firstPage",
1591
+ previous: "previousPage",
1592
+ next: "nextPage",
1593
+ last: "lastPage"
1594
+ };
1579
1595
  function PaginationBarCore({ table, labels, pageSizeOptions, size, className, style }) {
1580
1596
  const pageSizeLabelId = useId();
1581
1597
  const { pageIndex, pageSize } = table.atoms.pagination.get();
@@ -1591,7 +1607,7 @@ function PaginationBarCore({ table, labels, pageSizeOptions, size, className, st
1591
1607
  style,
1592
1608
  wrap: "wrap",
1593
1609
  children: [/* @__PURE__ */ jsx(Text, {
1594
- c: "dimmed",
1610
+ c: "var(--ledger-color-dimmed)",
1595
1611
  size,
1596
1612
  children: labels.paginationSummary(from, to, total)
1597
1613
  }), /* @__PURE__ */ jsxs(Group, {
@@ -1601,7 +1617,7 @@ function PaginationBarCore({ table, labels, pageSizeOptions, size, className, st
1601
1617
  gap: "xs",
1602
1618
  wrap: "nowrap",
1603
1619
  children: [/* @__PURE__ */ jsx(Text, {
1604
- c: "dimmed",
1620
+ c: "var(--ledger-color-dimmed)",
1605
1621
  id: pageSizeLabelId,
1606
1622
  size,
1607
1623
  children: labels.rowsPerPage
@@ -1615,6 +1631,9 @@ function PaginationBarCore({ table, labels, pageSizeOptions, size, className, st
1615
1631
  onChange: (value) => value !== null && table.setPageSize(Number(value))
1616
1632
  })]
1617
1633
  }), /* @__PURE__ */ jsx(Pagination, {
1634
+ getControlProps: (control) => {
1635
+ return { "aria-label": labels[CONTROL_LABELS[control]] };
1636
+ },
1618
1637
  size: SIZES[size].control,
1619
1638
  total: pageCount,
1620
1639
  value: pageIndex + 1,
@@ -3036,6 +3055,14 @@ function autosizeColumn(setColumnSizing, { columnId, minSize, maxSize, hasFilter
3036
3055
  * a black box that may ship no clear of its own — keeps the popover-level fallback.
3037
3056
  */
3038
3057
  const FACETED_OPTIONS_CAP = 100;
3058
+ /**
3059
+ * The smallest pointer target WCAG 2.2 AA accepts without spacing around it, in px.
3060
+ */
3061
+ const MIN_TARGET_SIZE = 24;
3062
+ /**
3063
+ * The calendar's weekend color, as the variable Mantine's day rule reads (see DateRangeFilter).
3064
+ */
3065
+ const WEEKEND_COLOR = { "--mantine-color-red-6": "color-mix(in srgb, var(--mantine-color-red-text), var(--mantine-color-text) 30%)" };
3039
3066
  function FilterPopover({ column }) {
3040
3067
  const { labels, icons, getStyles, filterMode, size } = useDataTableContext();
3041
3068
  const filter = column.columnDef.meta?.filter;
@@ -3049,6 +3076,8 @@ function FilterPopover({ column }) {
3049
3076
  children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(ActionIcon, {
3050
3077
  "aria-label": name,
3051
3078
  "data-active": active || void 0,
3079
+ mih: MIN_TARGET_SIZE,
3080
+ miw: MIN_TARGET_SIZE,
3052
3081
  size: SIZES[size].control,
3053
3082
  variant: active ? "light" : "subtle",
3054
3083
  onClick: (event) => event.stopPropagation(),
@@ -3230,11 +3259,21 @@ function DateRangeFilter({ column, name }) {
3230
3259
  const filterValue = column.getFilterValue();
3231
3260
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(DatePicker, {
3232
3261
  allowSingleDateInRange: true,
3262
+ hideOutsideDates: true,
3233
3263
  highlightToday: true,
3234
3264
  "aria-label": name,
3235
3265
  size: "xs",
3266
+ style: WEEKEND_COLOR,
3236
3267
  type: "range",
3237
3268
  value: filterValue ?? [null, null],
3269
+ ariaLabels: {
3270
+ previousMonth: labels.previousMonth,
3271
+ nextMonth: labels.nextMonth,
3272
+ previousYear: labels.previousYear,
3273
+ nextYear: labels.nextYear,
3274
+ previousDecade: labels.previousDecade,
3275
+ nextDecade: labels.nextDecade
3276
+ },
3238
3277
  onChange: (next) => column.setFilterValue(!next[0] && !next[1] ? void 0 : next)
3239
3278
  }), filterValue !== void 0 && /* @__PURE__ */ jsx(Group, {
3240
3279
  justify: "flex-end",
@@ -3812,6 +3851,24 @@ const builtInFilterFns = {
3812
3851
  startsWith: filterFn_startsWith,
3813
3852
  weakEquals: filterFn_weakEquals
3814
3853
  };
3854
+ /**
3855
+ * Typed through the exported definitions on purpose: since 9.2 several of their value types
3856
+ * name an alias TanStack does not export, and an inferred registry would carry that alias into
3857
+ * ledger's declaration files, where no consumer can resolve it.
3858
+ */
3859
+ const builtInAggregationFns = {
3860
+ count: aggregationFn_count,
3861
+ extent: aggregationFn_extent,
3862
+ first: aggregationFn_first,
3863
+ last: aggregationFn_last,
3864
+ max: aggregationFn_max,
3865
+ mean: aggregationFn_mean,
3866
+ median: aggregationFn_median,
3867
+ min: aggregationFn_min,
3868
+ sum: aggregationFn_sum,
3869
+ unique: aggregationFn_unique,
3870
+ uniqueCount: aggregationFn_uniqueCount
3871
+ };
3815
3872
  const ledgerFeatures = tableFeatures({
3816
3873
  cellSpanningFeature,
3817
3874
  columnFacetingFeature,
@@ -3836,19 +3893,7 @@ const ledgerFeatures = tableFeatures({
3836
3893
  groupedRowModel: createGroupedRowModel(),
3837
3894
  paginatedRowModel: createPaginatedRowModel(),
3838
3895
  sortedRowModel: createSortedRowModel(),
3839
- aggregationFns: {
3840
- count: aggregationFn_count,
3841
- extent: aggregationFn_extent,
3842
- first: aggregationFn_first,
3843
- last: aggregationFn_last,
3844
- max: aggregationFn_max,
3845
- mean: aggregationFn_mean,
3846
- median: aggregationFn_median,
3847
- min: aggregationFn_min,
3848
- sum: aggregationFn_sum,
3849
- unique: aggregationFn_unique,
3850
- uniqueCount: aggregationFn_uniqueCount
3851
- },
3896
+ aggregationFns: builtInAggregationFns,
3852
3897
  filterFns: {
3853
3898
  ...builtInFilterFns,
3854
3899
  ...ledgerFilterFns
@@ -6369,6 +6414,33 @@ function useStylesRevision(getStyles, selectors) {
6369
6414
  return revision;
6370
6415
  }
6371
6416
  //#endregion
6417
+ //#region src/use-viewport-overflow.ts
6418
+ /**
6419
+ * Whether the body viewport scrolls on either axis. A scroll container has to be reachable by
6420
+ * keyboard to be scrolled by it (WCAG 2.1.1), while a focus stop over content that fits is a
6421
+ * Tab press spent on nothing — so the viewport's focus stop follows this.
6422
+ *
6423
+ * Measured whenever the viewport or its content resizes: rows arriving, columns widening, or
6424
+ * the host resizing the table each change the answer without a scroll event. A 1px tolerance
6425
+ * absorbs fractional layout rounding, which would otherwise flicker the stop on and off.
6426
+ */
6427
+ function useViewportOverflow(viewport) {
6428
+ const [overflowing, setOverflowing] = useState(false);
6429
+ useLayoutEffect(() => {
6430
+ if (!viewport) return;
6431
+ const measure = () => {
6432
+ const next = viewport.scrollHeight - viewport.clientHeight > 1 || viewport.scrollWidth - viewport.clientWidth > 1;
6433
+ setOverflowing(next);
6434
+ };
6435
+ measure();
6436
+ const observer = new ResizeObserver(measure);
6437
+ observer.observe(viewport);
6438
+ if (viewport.firstElementChild) observer.observe(viewport.firstElementChild);
6439
+ return () => observer.disconnect();
6440
+ }, [viewport]);
6441
+ return overflowing;
6442
+ }
6443
+ //#endregion
6372
6444
  //#region src/data-table.tsx
6373
6445
  /**
6374
6446
  * The root component (docs/api.md): a generic Mantine factory with full Styles API,
@@ -6426,7 +6498,7 @@ const STYLE_SELECTORS = Object.keys(classes);
6426
6498
  */
6427
6499
  const NO_ARIA_ROWS = [];
6428
6500
  const EMPTY_STATE_STYLES = { title: {
6429
- color: "var(--mantine-color-dimmed)",
6501
+ color: "var(--ledger-color-dimmed)",
6430
6502
  fontWeight: 500
6431
6503
  } };
6432
6504
  const defaultProps = {
@@ -6618,6 +6690,7 @@ function DataTableCore({ presentation, stylesProps, table }) {
6618
6690
  viewportRef.current = element;
6619
6691
  setViewport(element);
6620
6692
  }, []);
6693
+ const viewportOverflows = useViewportOverflow(viewport);
6621
6694
  const startLeafColumns = table.getStartVisibleLeafColumns();
6622
6695
  const endLeafColumns = table.getEndVisibleLeafColumns();
6623
6696
  const displayColumns = [
@@ -6833,7 +6906,7 @@ function DataTableCore({ presentation, stylesProps, table }) {
6833
6906
  rowPinningActive,
6834
6907
  withDetailPanels
6835
6908
  ]);
6836
- const bodyAriaRowCount = loading && logicalDisplayRowCount === 0 ? skeletonRowCount : logicalDisplayRowCount + (loadMoreError || loadingMore ? 1 : 0);
6909
+ const bodyAriaRowCount = loading && logicalDisplayRowCount === 0 ? skeletonRowCount : logicalDisplayRowCount + (loadMoreError || loadingMore ? 1 : 0) + (isEmpty || errorActive ? 1 : 0);
6837
6910
  const footerRowCount = visibleFooterGroups(table).length;
6838
6911
  const ariaRowCount = headerRowCount + bodyAriaRowCount + footerRowCount;
6839
6912
  const footerAriaRowIndexStart = headerRowCount + bodyAriaRowCount + 1;
@@ -7207,11 +7280,10 @@ function DataTableCore({ presentation, stylesProps, table }) {
7207
7280
  },
7208
7281
  viewportProps: mergeElementProps(viewportProps, {
7209
7282
  style: { overscrollBehavior: "none" },
7283
+ role: "rowgroup",
7210
7284
  "aria-describedby": viewportDescribedBy,
7211
- ...activeRowEnabled && {
7212
- tabIndex: 0,
7213
- onKeyDown: handleActiveRowKeyDown
7214
- }
7285
+ tabIndex: activeRowEnabled || viewportOverflows ? 0 : void 0,
7286
+ ...activeRowEnabled && { onKeyDown: handleActiveRowKeyDown }
7215
7287
  }),
7216
7288
  onScrollPositionChange: handleScrollPositionChange,
7217
7289
  children: [
@@ -7234,43 +7306,59 @@ function DataTableCore({ presentation, stylesProps, table }) {
7234
7306
  })]
7235
7307
  }),
7236
7308
  isEmpty && /* @__PURE__ */ jsx("div", {
7237
- ...getStyles("empty"),
7238
- "data-variant": filtersActive ? "no-results" : "no-data",
7239
- role: "status",
7240
- children: emptyState ?? /* @__PURE__ */ jsx(EmptyState, {
7241
- withIndicatorBackground: true,
7242
- size: "sm",
7243
- styles: EMPTY_STATE_STYLES,
7244
- title: filtersActive ? labels.noResults : labels.empty,
7245
- icon: filtersActive ? /* @__PURE__ */ jsx(icons.noResults, {
7246
- size: 40,
7247
- strokeWidth: 1.5
7248
- }) : /* @__PURE__ */ jsx(icons.empty, {
7249
- size: 40,
7250
- strokeWidth: 1.5
7309
+ "aria-rowindex": virtualEnabled ? headerRowCount + bodyAriaRowCount : void 0,
7310
+ role: "row",
7311
+ children: /* @__PURE__ */ jsx("div", {
7312
+ ...getStyles("empty"),
7313
+ "aria-colspan": visibleLeafColumns.length,
7314
+ "data-variant": filtersActive ? "no-results" : "no-data",
7315
+ role: "cell",
7316
+ children: /* @__PURE__ */ jsx("div", {
7317
+ role: "status",
7318
+ children: emptyState ?? /* @__PURE__ */ jsx(EmptyState, {
7319
+ withIndicatorBackground: true,
7320
+ size: "sm",
7321
+ styles: EMPTY_STATE_STYLES,
7322
+ title: filtersActive ? labels.noResults : labels.empty,
7323
+ icon: filtersActive ? /* @__PURE__ */ jsx(icons.noResults, {
7324
+ size: 40,
7325
+ strokeWidth: 1.5
7326
+ }) : /* @__PURE__ */ jsx(icons.empty, {
7327
+ size: 40,
7328
+ strokeWidth: 1.5
7329
+ })
7330
+ })
7251
7331
  })
7252
7332
  })
7253
7333
  }),
7254
7334
  errorActive && /* @__PURE__ */ jsx("div", {
7255
- ...getStyles("empty"),
7256
- "data-over-rows": rowsLength > 0 || void 0,
7257
- "data-variant": "error",
7258
- role: "alert",
7259
- children: /* @__PURE__ */ jsx(EmptyState, {
7260
- withIndicatorBackground: true,
7261
- icon: /* @__PURE__ */ jsx(icons.error, {
7262
- size: 40,
7263
- strokeWidth: 1.5
7264
- }),
7265
- size: "sm",
7266
- styles: EMPTY_STATE_STYLES,
7267
- title: error === true ? labels.error : error,
7268
- children: onRetry && /* @__PURE__ */ jsx(Button, {
7269
- leftSection: /* @__PURE__ */ jsx(icons.retry, { size: 14 }),
7270
- size: "xs",
7271
- variant: "light",
7272
- onClick: onRetry,
7273
- children: labels.retry
7335
+ "aria-rowindex": virtualEnabled ? headerRowCount + bodyAriaRowCount : void 0,
7336
+ role: "row",
7337
+ children: /* @__PURE__ */ jsx("div", {
7338
+ ...getStyles("empty"),
7339
+ "aria-colspan": visibleLeafColumns.length,
7340
+ "data-over-rows": rowsLength > 0 || void 0,
7341
+ "data-variant": "error",
7342
+ role: "cell",
7343
+ children: /* @__PURE__ */ jsx("div", {
7344
+ role: "alert",
7345
+ children: /* @__PURE__ */ jsx(EmptyState, {
7346
+ withIndicatorBackground: true,
7347
+ icon: /* @__PURE__ */ jsx(icons.error, {
7348
+ size: 40,
7349
+ strokeWidth: 1.5
7350
+ }),
7351
+ size: "sm",
7352
+ styles: EMPTY_STATE_STYLES,
7353
+ title: error === true ? labels.error : error,
7354
+ children: onRetry && /* @__PURE__ */ jsx(Button, {
7355
+ leftSection: /* @__PURE__ */ jsx(icons.retry, { size: 14 }),
7356
+ size: "xs",
7357
+ variant: "light",
7358
+ onClick: onRetry,
7359
+ children: labels.retry
7360
+ })
7361
+ })
7274
7362
  })
7275
7363
  })
7276
7364
  })