@mendylanda/ui 0.3.2-dev.56.581b055ea0a9 → 0.3.2-dev.58.0ef9785a4046

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.
Files changed (50) hide show
  1. package/README.md +15 -0
  2. package/dist/calendar-locale.d.ts +7 -0
  3. package/dist/calendar-locale.js +31 -0
  4. package/dist/class-names.js +1 -1
  5. package/dist/customization.d.ts +6 -1
  6. package/dist/customization.js +20 -2
  7. package/dist/filters/filter-bar.d.ts +1 -1
  8. package/dist/filters/filter-bar.js +56 -30
  9. package/dist/filters/filter-collection.js +3 -1
  10. package/dist/filters/filter-date-editor.js +5 -3
  11. package/dist/filters/filter-definition.d.ts +3 -2
  12. package/dist/filters/filter-definition.js +5 -6
  13. package/dist/filters/filter-menu-focus.js +1 -1
  14. package/dist/filters/filter-menu-panel.js +13 -9
  15. package/dist/filters/filter-select-editor.js +6 -4
  16. package/dist/filters/filter-text-editor.js +5 -3
  17. package/dist/filters/filters.js +8 -5
  18. package/dist/filters/index.d.ts +3 -0
  19. package/dist/filters/index.js +2 -0
  20. package/dist/filters/use-filter-options.d.ts +1 -1
  21. package/dist/filters/use-filter-options.js +13 -7
  22. package/dist/filters/use-filters.js +6 -2
  23. package/dist/filters/use-url-filters.js +9 -7
  24. package/dist/locale-context.d.ts +29 -0
  25. package/dist/locale-context.js +8 -0
  26. package/dist/locale.d.ts +37 -0
  27. package/dist/locale.js +26 -0
  28. package/dist/locales/en.d.ts +113 -0
  29. package/dist/locales/en.js +112 -0
  30. package/dist/locales/he.d.ts +116 -0
  31. package/dist/locales/he.js +116 -0
  32. package/dist/primitives/calendar.d.ts +1 -1
  33. package/dist/primitives/calendar.js +15 -10
  34. package/dist/primitives/dropdown-menu.js +7 -5
  35. package/dist/primitives/popover.js +3 -1
  36. package/dist/styles.css +39 -39
  37. package/dist/styles.tailwind3.css +39 -39
  38. package/dist/table/table-column-settings.js +27 -13
  39. package/dist/table/table-controls.js +21 -8
  40. package/dist/table/table-feedback.js +6 -3
  41. package/dist/table/table-frame.js +3 -1
  42. package/dist/table/table-layout.d.ts +1 -1
  43. package/dist/table/table-layout.js +5 -5
  44. package/dist/table/table-loading.js +3 -1
  45. package/dist/table/table-parts.js +15 -11
  46. package/dist/table/table-view.js +6 -4
  47. package/dist/table/use-column-window.js +1 -1
  48. package/dist/table/use-data-table.js +3 -0
  49. package/dist/table/use-table-interaction.js +12 -8
  50. package/package.json +8 -2
@@ -1,6 +1,6 @@
1
1
  import { distributeColumnWidths } from "./column-widths.js";
2
2
  /** Keep headers, skeletons, and loaded cells on the same column geometry. */
3
- export function tableLayout(table, viewportWidth, rowHeight) {
3
+ export function tableLayout(table, viewportWidth, rowHeight, direction = "ltr") {
4
4
  const columns = [
5
5
  ...table.getStartVisibleLeafColumns(),
6
6
  ...table.getCenterVisibleLeafColumns(),
@@ -28,12 +28,12 @@ export function tableLayout(table, viewportWidth, rowHeight) {
28
28
  const positions = new Map();
29
29
  let offset = 0;
30
30
  for (const column of table.getStartVisibleLeafColumns()) {
31
- positions.set(column.id, { side: "left", offset });
31
+ positions.set(column.id, { side: direction === "rtl" ? "right" : "left", offset });
32
32
  offset += size(column);
33
33
  }
34
34
  offset = 0;
35
35
  for (const column of [...table.getEndVisibleLeafColumns()].reverse()) {
36
- positions.set(column.id, { side: "right", offset });
36
+ positions.set(column.id, { side: direction === "rtl" ? "left" : "right", offset });
37
37
  offset += size(column);
38
38
  }
39
39
  const styles = new Map();
@@ -54,10 +54,10 @@ export function tableLayout(table, viewportWidth, rowHeight) {
54
54
  [pin.side]: pin.offset,
55
55
  zIndex: 2,
56
56
  ...(column.id === table.getStartVisibleLeafColumns().at(-1)?.id
57
- ? { borderRightWidth: 4 }
57
+ ? { [direction === "rtl" ? "borderLeftWidth" : "borderRightWidth"]: 4 }
58
58
  : {}),
59
59
  ...(column.id === table.getEndVisibleLeafColumns()[0]?.id
60
- ? { borderLeftWidth: 4 }
60
+ ? { [direction === "rtl" ? "borderRightWidth" : "borderLeftWidth"]: 4 }
61
61
  : {}),
62
62
  }
63
63
  : {}),
@@ -1,6 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMendyLocale } from "../locale-context.js";
2
3
  import { Fragment } from "react";
3
4
  /** Loading shares the live column geometry and its single scroll container. */
4
5
  export function TableLoadingRows({ columns, columnGaps, count, width, rowHeight, cellStyle, }) {
5
- return (_jsx("div", { role: "status", "aria-label": "Loading rows", className: "mui-2bf6510f1330", style: { width }, children: Array.from({ length: count }, (_, index) => (_jsx("div", { "aria-hidden": "true", "data-slot": "table-loading-row", className: "mui-222f930b8752 mui-2bf6510f1330", style: { height: rowHeight }, children: columns.map((column) => (_jsxs(Fragment, { children: [columnGaps.has(column.id) && (_jsx("div", { "aria-hidden": "true", className: "mui-27ead27a81df", style: { width: columnGaps.get(column.id) } })), _jsx("div", { "data-slot": "table-loading-cell", "data-column-id": column.id, className: "mui-222f930b8752 mui-27ead27a81df mui-71556df3b421 mui-bbe39cfb5cc6 mui-3b6d5fc7b061 mui-5b272f3c5076 mui-0f9e6672913a", style: cellStyle(column), children: _jsx("div", { className: "mui-2edce89ef182 mui-56bb14cbd1fe mui-7b3cd77eb999 mui-02e603944040 mui-87ecb59f2d2d mui-237747164b60" }) }, column.id)] }, column.id))) }, index))) }));
6
+ const { t } = useMendyLocale();
7
+ return (_jsx("div", { role: "status", "aria-label": t("loadingRows"), className: "mui-2bf6510f1330", style: { width }, children: Array.from({ length: count }, (_, index) => (_jsx("div", { "aria-hidden": "true", "data-slot": "table-loading-row", className: "mui-222f930b8752 mui-2bf6510f1330", style: { height: rowHeight }, children: columns.map((column) => (_jsxs(Fragment, { children: [columnGaps.has(column.id) && (_jsx("div", { "aria-hidden": "true", className: "mui-27ead27a81df", style: { width: columnGaps.get(column.id) } })), _jsx("div", { "data-slot": "table-loading-cell", "data-column-id": column.id, className: "mui-222f930b8752 mui-27ead27a81df mui-71556df3b421 mui-bbe39cfb5cc6 mui-3b6d5fc7b061 mui-5b272f3c5076 mui-0f9e6672913a", style: cellStyle(column), children: _jsx("div", { className: "mui-2edce89ef182 mui-56bb14cbd1fe mui-7b3cd77eb999 mui-02e603944040 mui-87ecb59f2d2d mui-237747164b60" }) }, column.id)] }, column.id))) }, index))) }));
6
8
  }
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useMendyLocale } from "../locale-context.js";
3
4
  import { Fragment, memo, useMemo } from "react";
4
5
  import { constructCell, flexRender } from "@tanstack/react-table";
5
6
  import { ArrowDown, ArrowUp } from "lucide-react";
@@ -8,13 +9,15 @@ import { Checkbox } from "../primitives/checkbox.js";
8
9
  import { cn } from "../utils.js";
9
10
  import { interactiveSelector } from "./clipboard.js";
10
11
  export function TableHeaderCell({ table, header, index, style, renderHeader, contentClassName, selectLoaded, }) {
12
+ const { t } = useMendyLocale();
11
13
  const column = header.column;
12
14
  const definition = column.columnDef;
13
15
  const title = definition.label ?? (typeof definition.header === "string" ? definition.header : column.id);
14
16
  const sorted = column.getIsSorted();
15
- return (_jsxs("div", { role: "columnheader", "data-column-id": column.id, "aria-colindex": index + 1, "aria-sort": sorted === "asc" ? "ascending" : sorted === "desc" ? "descending" : undefined, style: style, className: "mui-ad936fcbed63 mui-d2d9e1f13413 mui-222f930b8752 mui-27ead27a81df mui-71556df3b421 mui-19e97f3f40e6 mui-3b6d5fc7b061 mui-5b272f3c5076 mui-0f9e6672913a mui-daaac3fbf55e mui-35f35c41d134", children: [selectLoaded && index === 0 && (_jsx(Checkbox, { "aria-label": "Select loaded rows", disabled: selectLoaded.disabled, checked: selectLoaded.checked, onCheckedChange: (value) => table.toggleAllPageRowsSelected(value === true), className: "mui-477d8f4dfce9 mui-94f91922a10e mui-34a57d4b4103 mui-8da02faac748 mui-b8b1747fa763 mui-d2e4a66bb430 mui-978f422895e5 mui-d0c2ae8419e1 mui-e2ed522ed9b7 mui-fa8e1efead3c mui-eaedb91f8774" })), _jsx("div", { className: cn("mui-184ddc11e5f9 mui-7bd5bab6d7f4 mui-d5111d0e9f48", (renderHeader || typeof definition.header === "function") && contentClassName), children: _jsx(TableHeaderContent, { header: header, renderHeader: renderHeader, title: title }) }), column.getCanResize() && (_jsx(TableResizeHandle, { table: table, header: header, title: title, width: Number(style.width) }))] }, column.id));
17
+ return (_jsxs("div", { role: "columnheader", "data-column-id": column.id, "aria-colindex": index + 1, "aria-sort": sorted === "asc" ? "ascending" : sorted === "desc" ? "descending" : undefined, style: style, className: "mui-ad936fcbed63 mui-d2d9e1f13413 mui-222f930b8752 mui-27ead27a81df mui-71556df3b421 mui-19e97f3f40e6 mui-3b6d5fc7b061 mui-5b272f3c5076 mui-0f9e6672913a mui-daaac3fbf55e mui-35f35c41d134", children: [selectLoaded && index === 0 && (_jsx(Checkbox, { "aria-label": t("selectLoaded"), disabled: selectLoaded.disabled, checked: selectLoaded.checked, onCheckedChange: (value) => table.toggleAllPageRowsSelected(value === true), className: "mui-477d8f4dfce9 mui-94f91922a10e mui-34a57d4b4103 mui-8da02faac748 mui-b8b1747fa763 mui-d2e4a66bb430 mui-978f422895e5 mui-d0c2ae8419e1 mui-e2ed522ed9b7 mui-fa8e1efead3c mui-eaedb91f8774" })), _jsx("div", { className: cn("mui-184ddc11e5f9 mui-7bd5bab6d7f4 mui-d5111d0e9f48", (renderHeader || typeof definition.header === "function") && contentClassName), children: _jsx(TableHeaderContent, { header: header, renderHeader: renderHeader, title: title }) }), column.getCanResize() && (_jsx(TableResizeHandle, { table: table, header: header, title: title, width: Number(style.width) }))] }, column.id));
16
18
  }
17
19
  function TableBodyRowImpl({ row, rowIndex, start, rowHeight, autoRowHeight, measureElement, rowClassName, renderRowDetail, detailWidth, cellStyle, columns, columnGaps, columnIndexes, contentVersion, contentState, focusedId, copied, contentClassName, onRowClick, onRowActivate, isRowHighlighted, inlineSelection, }) {
20
+ const { t, direction } = useMendyLocale();
18
21
  // The engine's getAllCells API eagerly allocates every column. Build only the
19
22
  // viewport cells with its public constructor, and release them with this row.
20
23
  const cache = useMemo(() => new WeakMap(), [row]);
@@ -26,7 +29,7 @@ function TableBodyRowImpl({ row, rowIndex, start, rowHeight, autoRowHeight, meas
26
29
  }
27
30
  return cell;
28
31
  });
29
- const rowElement = (_jsx("div", { ref: renderRowDetail ? undefined : measureElement, role: "row", "aria-rowindex": renderRowDetail ? undefined : rowIndex + 2, "aria-selected": row.getIsSelected(), "data-highlighted": row.getIsSelected() || isRowHighlighted?.(row.original), "data-index": rowIndex, className: cn("mui-ad936fcbed63 mui-635702706586 mui-222f930b8752 mui-2bf6510f1330 mui-5b272f3c5076 mui-37ad15a95595 mui-9d7d1760cd8e", rowClassName?.(row.original)), style: {
32
+ const rowElement = (_jsx("div", { ref: renderRowDetail ? undefined : measureElement, role: "row", "aria-rowindex": renderRowDetail ? undefined : rowIndex + 2, "aria-selected": row.getIsSelected(), "data-highlighted": row.getIsSelected() || isRowHighlighted?.(row.original), "data-index": rowIndex, className: cn("mui-ad936fcbed63 mui-8368bbb62f66 mui-222f930b8752 mui-2bf6510f1330 mui-5b272f3c5076 mui-37ad15a95595 mui-9d7d1760cd8e", rowClassName?.(row.original)), style: {
30
33
  height: autoRowHeight ? undefined : rowHeight,
31
34
  minHeight: rowHeight,
32
35
  top: renderRowDetail ? 0 : start,
@@ -64,21 +67,22 @@ function TableBodyRowImpl({ row, rowIndex, start, rowHeight, autoRowHeight, meas
64
67
  }, children: [selected && (_jsx("span", { "aria-hidden": "true", "data-selection-outline": "", className: "mui-33228ff7d583 mui-747355bdc2a2 mui-d7efd1b0b0f9 mui-515f9fdc6db7", style: {
65
68
  top: edge?.top ? 0 : -1,
66
69
  bottom: edge?.bottom ? -1 : -2,
67
- left: -Number(cellStyle(cell.column).borderLeftWidth ?? 0),
68
- right: -Number(cellStyle(cell.column).borderRightWidth ?? 1),
70
+ left: -Number(cellStyle(cell.column).borderLeftWidth ?? (direction === "rtl" ? 1 : 0)),
71
+ right: -Number(cellStyle(cell.column).borderRightWidth ?? (direction === "rtl" ? 0 : 1)),
69
72
  borderTopWidth: edge?.top ? 2 : 0,
70
73
  borderBottomWidth: edge?.bottom ? 2 : 0,
71
- borderLeftWidth: edge?.left ? 2 : 0,
72
- borderRightWidth: edge?.right ? 2 : 0,
73
- } })), inlineSelection && index === 0 && (_jsx(Checkbox, { "aria-label": `Select row ${rowIndex + 1}`, checked: row.getIsSelected(), disabled: !row.getCanSelect(), onCheckedChange: (value) => row.toggleSelected(value === true), onMouseDown: (event) => event.stopPropagation(), onClick: (event) => event.stopPropagation(), className: "mui-68d781378b03 mui-94f91922a10e mui-34a57d4b4103 mui-8da02faac748 mui-b8b1747fa763 mui-d2e4a66bb430 mui-978f422895e5 mui-d0c2ae8419e1 mui-9c02852bfc55 mui-e2ed522ed9b7 mui-cbd3aed703f7 mui-fa8e1efead3c mui-eaedb91f8774" })), _jsx("div", { className: cn("mui-184ddc11e5f9 mui-81b198a2db84", autoRowHeight ? "mui-726fca123972 mui-37cf9655f30a mui-b5edc3ea7c91" : "mui-7bd696ca6be3 mui-5a3a4ee420c2", contentClassName), children: _jsx(TableCellContent, { cell: cell, renderer: cell.column.columnDef.cell, version: contentVersion, state: contentState }) })] }, cell.id)] }, cell.id));
74
+ borderLeftWidth: (direction === "rtl" ? edge?.right : edge?.left) ? 2 : 0,
75
+ borderRightWidth: (direction === "rtl" ? edge?.left : edge?.right) ? 2 : 0,
76
+ } })), inlineSelection && index === 0 && (_jsx(Checkbox, { "aria-label": t("selectRow", { id: rowIndex + 1 }), checked: row.getIsSelected(), disabled: !row.getCanSelect(), onCheckedChange: (value) => row.toggleSelected(value === true), onMouseDown: (event) => event.stopPropagation(), onClick: (event) => event.stopPropagation(), className: "mui-68d781378b03 mui-94f91922a10e mui-34a57d4b4103 mui-8da02faac748 mui-b8b1747fa763 mui-d2e4a66bb430 mui-978f422895e5 mui-d0c2ae8419e1 mui-9c02852bfc55 mui-e2ed522ed9b7 mui-cbd3aed703f7 mui-fa8e1efead3c mui-eaedb91f8774" })), _jsx("div", { className: cn("mui-184ddc11e5f9 mui-81b198a2db84", autoRowHeight ? "mui-726fca123972 mui-37cf9655f30a mui-b5edc3ea7c91" : "mui-7bd696ca6be3 mui-5a3a4ee420c2", contentClassName), children: _jsx(TableCellContent, { cell: cell, renderer: cell.column.columnDef.cell, version: contentVersion, state: contentState }) })] }, cell.id)] }, cell.id));
74
77
  }) }, row.id));
75
78
  if (!renderRowDetail)
76
79
  return rowElement;
77
80
  const detail = renderRowDetail(row.original);
78
- return (_jsxs("div", { ref: measureElement, "data-index": rowIndex, role: "rowgroup", className: "mui-747355bdc2a2 mui-635702706586 mui-2bf6510f1330", style: { top: start }, children: [rowElement, detail != null && (_jsx("div", { role: "row", className: "mui-bbe39cfb5cc6 mui-5b272f3c5076", children: _jsx("div", { role: "gridcell", "aria-colspan": columns.length, className: "mui-964a9431ff49 mui-184ddc11e5f9 mui-094f5333853b", style: { width: detailWidth, maxWidth: "100%", insetInlineStart: 0 }, children: detail }) }))] }));
81
+ return (_jsxs("div", { ref: measureElement, "data-index": rowIndex, role: "rowgroup", className: "mui-747355bdc2a2 mui-8368bbb62f66 mui-2bf6510f1330", style: { top: start }, children: [rowElement, detail != null && (_jsx("div", { role: "row", className: "mui-bbe39cfb5cc6 mui-5b272f3c5076", children: _jsx("div", { role: "gridcell", "aria-colspan": columns.length, className: "mui-964a9431ff49 mui-184ddc11e5f9 mui-094f5333853b", style: { width: detailWidth, maxWidth: "100%", insetInlineStart: 0 }, children: detail }) }))] }));
79
82
  }
80
83
  export const TableBodyRow = memo(TableBodyRowImpl);
81
84
  function TableResizeHandle({ table, header, title, width, }) {
85
+ const { t, direction } = useMendyLocale();
82
86
  const column = header.column;
83
87
  const beginResize = (event) => {
84
88
  if ("touches" in event && event.touches.length > 1)
@@ -98,16 +102,16 @@ function TableResizeHandle({ table, header, title, width, }) {
98
102
  columnSizingStart: [[column.id, width]],
99
103
  }));
100
104
  };
101
- return (_jsx("div", { role: "separator", tabIndex: 0, "aria-label": `Resize ${title}`, "aria-orientation": "vertical", "aria-valuenow": Math.round(width), "aria-valuemin": column.columnDef.minSize ?? 48, "aria-valuemax": column.columnDef.maxSize ?? 1200, onDoubleClick: () => column.resetSize(), onMouseDown: beginResize, onTouchStart: beginResize, onKeyDown: (event) => {
105
+ return (_jsx("div", { role: "separator", tabIndex: 0, "aria-label": t("resizeColumn", { label: title }), "aria-orientation": "vertical", "aria-valuenow": Math.round(width), "aria-valuemin": column.columnDef.minSize ?? 48, "aria-valuemax": column.columnDef.maxSize ?? 1200, onDoubleClick: () => column.resetSize(), onMouseDown: beginResize, onTouchStart: beginResize, onKeyDown: (event) => {
102
106
  if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
103
107
  event.preventDefault();
104
108
  event.stopPropagation();
105
109
  table.setColumnSizing((sizes) => ({
106
110
  ...sizes,
107
- [column.id]: Math.min(column.columnDef.maxSize ?? 1200, Math.max(column.columnDef.minSize ?? 48, width + (event.key === "ArrowLeft" ? -10 : 10))),
111
+ [column.id]: Math.min(column.columnDef.maxSize ?? 1200, Math.max(column.columnDef.minSize ?? 48, width + (event.key === "ArrowLeft" ? -10 : 10) * (direction === "rtl" ? -1 : 1))),
108
112
  }));
109
113
  }
110
- }, className: "mui-747355bdc2a2 mui-eb9e48c5dda9 mui-a74c4477017c mui-418e44ad4f9e mui-d4ea834145ae mui-2194d094b585 mui-739a9a000791 mui-78905c9e865c mui-4273133a876a mui-2f669cfad5aa mui-2e357972fc10" }));
114
+ }, className: "mui-747355bdc2a2 mui-eb9e48c5dda9 mui-aa7bcba08429 mui-418e44ad4f9e mui-d4ea834145ae mui-2194d094b585 mui-739a9a000791 mui-78905c9e865c mui-4273133a876a mui-2f669cfad5aa mui-2e357972fc10" }));
111
115
  }
112
116
  function TableHeaderContent({ header, renderHeader, title, }) {
113
117
  const column = header.column;
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useMendyLocale } from "../locale-context.js";
3
4
  import { Fragment, useCallback, useEffect, useLayoutEffect, useMemo, useRef } from "react";
4
5
  import { useVirtualizer } from "@tanstack/react-virtual";
5
6
  import { TableHeaderCell, TableBodyRow } from "./table-parts.js";
@@ -14,7 +15,8 @@ import { useTableInteraction } from "./use-table-interaction.js";
14
15
  import { useTableResults } from "./use-table-results.js";
15
16
  import { useInlineRowSelection } from "./use-inline-row-selection.js";
16
17
  import { TableFrame } from "./table-frame.js";
17
- export function TableView({ table, label = "Data table", height = "auto", layout: layoutMode = "content", footer, rowHeight: rowHeightOption = 44, rowClassName, renderRowDetail, className, contentClassName, emptyState, loadingState, scrollRef, status = "ready", refreshing, error, retry, loadMore, queryKey, filters, renderHeader, onRowClick, onRowActivate, isRowHighlighted, rowSelectionControls = true, onCopyError, }) {
18
+ export function TableView({ table, label, height = "auto", layout: layoutMode = "content", footer, rowHeight: rowHeightOption = 44, rowClassName, renderRowDetail, className, contentClassName, emptyState, loadingState, scrollRef, status = "ready", refreshing, error, retry, loadMore, queryKey, filters, renderHeader, onRowClick, onRowActivate, isRowHighlighted, rowSelectionControls = true, onCopyError, }) {
19
+ const { t, direction, code } = useMendyLocale();
18
20
  const fill = layoutMode === "fill";
19
21
  const { resultKey, hasFilters, clearFilters } = useTableResults(table, queryKey, filters);
20
22
  const autoRowHeight = rowHeightOption === "auto" || Boolean(renderRowDetail);
@@ -46,7 +48,7 @@ export function TableView({ table, label = "Data table", height = "auto", layout
46
48
  const centerColumns = table.getCenterVisibleLeafColumns();
47
49
  const endColumns = table.getEndVisibleLeafColumns();
48
50
  const sizing = table.state.columnSizing;
49
- const layout = useMemo(() => tableLayout(table, viewportWidth, rowHeight), [table, startColumns, centerColumns, endColumns, sizing, viewportWidth, rowHeight]);
51
+ const layout = useMemo(() => tableLayout(table, viewportWidth, rowHeight, direction), [table, startColumns, centerColumns, endColumns, sizing, viewportWidth, rowHeight, direction]);
50
52
  const { totalWidth, pinningActive } = layout;
51
53
  const { inlineSelection, selectLoaded } = useInlineRowSelection(table, layout.columns, rowSelectionControls);
52
54
  const focused = table.getFocusedCell();
@@ -104,12 +106,12 @@ export function TableView({ table, label = "Data table", height = "auto", layout
104
106
  virtual,
105
107
  ]);
106
108
  const headersById = new Map(table.getFlatHeaders().map((header) => [header.column.id, header]));
107
- return (_jsxs(TableFrame, { layout: layoutMode, stretch: height === "100%", footer: footer, children: [_jsx("div", { "aria-live": "polite", className: "mui-32fb090591d9", children: announcement }), _jsxs("div", { ref: setContainer, role: "grid", tabIndex: -1, "aria-label": label, "aria-rowcount": renderRowDetail ? -1 : rows.length + 1 + feedbackRowCount, "aria-colcount": layout.columns.length, "aria-busy": status === "loading" || refreshing, style: {
109
+ return (_jsxs(TableFrame, { layout: layoutMode, stretch: height === "100%", footer: footer, children: [_jsx("div", { "aria-live": "polite", className: "mui-32fb090591d9", children: announcement }), _jsxs("div", { ref: setContainer, role: "grid", tabIndex: -1, "aria-label": label ?? t("dataTable"), dir: direction, lang: code, "aria-rowcount": renderRowDetail ? -1 : rows.length + 1 + feedbackRowCount, "aria-colcount": layout.columns.length, "aria-busy": status === "loading" || refreshing, style: {
108
110
  height: fill || height === "auto" ? undefined : height,
109
111
  maxHeight: !fill && height === "auto" ? "65dvh" : undefined,
110
112
  }, className: cn("mui-d2d9e1f13413 mui-014aadadffad mui-1a26a0d28420 mui-3fa8c572949b mui-4f1a55de40bc mui-5b272f3c5076 mui-c74ab393b96d mui-b30fc56058b6", fill && "mui-410da8dfa8ac mui-7bd5bab6d7f4", className), onKeyDown: onKeyDown, children: [_jsx("div", { role: "row", "aria-rowindex": 1, className: "mui-964a9431ff49 mui-98599e4ee250 mui-4e8f0a87a0dc mui-222f930b8752 mui-2bf6510f1330 mui-bbe39cfb5cc6 mui-5b272f3c5076", style: { width: totalWidth }, children: columns.map((column) => (_jsxs(Fragment, { children: [columnGaps.has(column.id) && (_jsx("div", { "aria-hidden": "true", className: "mui-27ead27a81df", style: { width: columnGaps.get(column.id) } })), _jsx(TableHeaderCell, { table: table, header: headersById.get(column.id), index: columnIndexes.get(column.id), style: cellStyle(column), renderHeader: renderHeader, contentClassName: contentClassName, selectLoaded: selectLoaded }, column.id)] }, column.id))) }), _jsx(TableInitialState, { columnCount: layout.columns.length, status: status, hasRows: rows.length > 0, loadingState: loadingState ?? (_jsx(TableLoadingRows, { columns: columns, columnGaps: columnGaps, width: totalWidth, rowHeight: rowHeight, cellStyle: cellStyle, count: !fill && height === "auto"
111
113
  ? 8
112
- : Math.max(1, Math.ceil(((virtual.scrollRect?.height ?? 400) - rowHeight) / rowHeight)) })), emptyState: emptyState, hasFilters: hasFilters, pageIndex: table.state.pagination.pageIndex, clearFilters: clearFilters, firstPage: () => table.setPageIndex(0), error: error, retry: retry }), _jsx("div", { role: "rowgroup", className: "mui-d2d9e1f13413 mui-2bf6510f1330", style: { height: virtual.getTotalSize(), width: totalWidth }, children: items.map((item) => (_jsx(TableBodyRow, { row: rows[item.index], rowIndex: item.index, start: item.start, rowHeight: rowHeight, autoRowHeight: autoRowHeight, measureElement: autoRowHeight ? virtual.measureElement : undefined, rowClassName: rowClassName, renderRowDetail: renderRowDetail, detailWidth: viewportWidth ?? totalWidth, cellStyle: cellStyle, columns: columns, columnGaps: columnGaps, columnIndexes: columnIndexes, contentVersion: table.options, contentState: table.state, focusedId: focused?.id, copied: copied, contentClassName: contentClassName, onRowClick: onRowClick, onRowActivate: onRowActivate, isRowHighlighted: isRowHighlighted, inlineSelection: inlineSelection }, item.key))) }), hasRefreshError && (_jsx(TableFeedbackRow, { columnCount: layout.columns.length, rowIndex: rows.length + 2, className: "mui-964a9431ff49 mui-30150dd033ab", children: _jsxs("div", { role: "alert", className: "mui-5b272f3c5076 mui-094f5333853b", children: [error ?? "Could not refresh rows.", retry && (_jsx(Button, { onClick: retry, variant: "outline", size: "sm", children: "Retry" }))] }) })), loadMore?.available && (_jsx(TableLoadMore, { loadMore: loadMore, columnCount: layout.columns.length, rowIndex: rows.length + 2 + Number(hasInitialFeedback || hasRefreshError), onLoad: () => {
114
+ : Math.max(1, Math.ceil(((virtual.scrollRect?.height ?? 400) - rowHeight) / rowHeight)) })), emptyState: emptyState, hasFilters: hasFilters, pageIndex: table.state.pagination.pageIndex, clearFilters: clearFilters, firstPage: () => table.setPageIndex(0), error: error, retry: retry }), _jsx("div", { role: "rowgroup", className: "mui-d2d9e1f13413 mui-2bf6510f1330", style: { height: virtual.getTotalSize(), width: totalWidth }, children: items.map((item) => (_jsx(TableBodyRow, { row: rows[item.index], rowIndex: item.index, start: item.start, rowHeight: rowHeight, autoRowHeight: autoRowHeight, measureElement: autoRowHeight ? virtual.measureElement : undefined, rowClassName: rowClassName, renderRowDetail: renderRowDetail, detailWidth: viewportWidth ?? totalWidth, cellStyle: cellStyle, columns: columns, columnGaps: columnGaps, columnIndexes: columnIndexes, contentVersion: table.options, contentState: table.state, focusedId: focused?.id, copied: copied, contentClassName: contentClassName, onRowClick: onRowClick, onRowActivate: onRowActivate, isRowHighlighted: isRowHighlighted, inlineSelection: inlineSelection }, item.key))) }), hasRefreshError && (_jsx(TableFeedbackRow, { columnCount: layout.columns.length, rowIndex: rows.length + 2, className: "mui-964a9431ff49 mui-30150dd033ab", children: _jsxs("div", { role: "alert", className: "mui-5b272f3c5076 mui-094f5333853b", children: [error ?? t("refreshError"), retry && (_jsx(Button, { onClick: retry, variant: "outline", size: "sm", children: t("retry") }))] }) })), loadMore?.available && (_jsx(TableLoadMore, { loadMore: loadMore, columnCount: layout.columns.length, rowIndex: rows.length + 2 + Number(hasInitialFeedback || hasRefreshError), onLoad: () => {
113
115
  requested.current = null;
114
116
  void Promise.resolve()
115
117
  .then(() => loadMore.load())
@@ -18,7 +18,7 @@ export function useColumnWindow(layout, container, viewportWidth, focusedColumn,
18
18
  const element = container.current;
19
19
  if (!element)
20
20
  return;
21
- const measure = () => setScrollLeft(element.scrollLeft);
21
+ const measure = () => setScrollLeft(Math.abs(element.scrollLeft));
22
22
  measure();
23
23
  element.addEventListener("scroll", measure, { passive: true });
24
24
  return () => element.removeEventListener("scroll", measure);
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
3
3
  import { useTable } from "@tanstack/react-table";
4
+ import { useMendyLocale } from "../locale-context.js";
4
5
  import { tableFeaturesDefault } from "./features.js";
5
6
  import { useStableArray } from "./use-stable-array.js";
6
7
  import { reconcilePreferences } from "./state.js";
@@ -28,6 +29,7 @@ export function applyTablePreferences(table, input) {
28
29
  table.setColumnPinning(value.columnPinning);
29
30
  }
30
31
  export function useDataTable({ rows: inputRows, columns: inputColumns, processing, preferences, ...options }) {
32
+ const { direction } = useMendyLocale();
31
33
  const rows = useStableArray(inputRows);
32
34
  const columns = useStableArray(inputColumns);
33
35
  const defaults = useMemo(() => reconcilePreferences(null, columns, options.initialState), [columns, options.initialState]);
@@ -37,6 +39,7 @@ export function useDataTable({ rows: inputRows, columns: inputColumns, processin
37
39
  data: rows,
38
40
  columns,
39
41
  defaultColumn: { size: 180, minSize: 48, maxSize: 1200, ...options.defaultColumn },
42
+ columnResizeDirection: options.columnResizeDirection ?? direction,
40
43
  columnResizeMode: options.columnResizeMode ?? "onChange",
41
44
  enableCellSelection: options.enableCellSelection ?? true,
42
45
  enableRowSelection: options.enableRowSelection ??
@@ -1,8 +1,10 @@
1
1
  "use client";
2
+ import { useMendyLocale } from "../locale-context.js";
2
3
  import { useEffect, useLayoutEffect, useRef, useState } from "react";
3
4
  import { interactiveSelector, selectedCellsText } from "./clipboard.js";
4
5
  export function useTableInteraction({ table, pinningActive, container, queryKey, onRowActivate, onCopyError, scrollToIndex, }) {
5
6
  const rows = table.getRowModel().rows;
7
+ const { t, direction: readingDirection } = useMendyLocale();
6
8
  const columns = [
7
9
  ...table.getStartVisibleLeafColumns(),
8
10
  ...table.getCenterVisibleLeafColumns(),
@@ -69,14 +71,14 @@ export function useTableInteraction({ table, pinningActive, container, queryKey,
69
71
  await navigator.clipboard.writeText(text);
70
72
  if (!mounted.current)
71
73
  return;
72
- setAnnouncement("Selected cells copied");
74
+ setAnnouncement(t("copied"));
73
75
  setCopied(true);
74
76
  clearTimeout(copyTimer.current);
75
77
  copyTimer.current = setTimeout(() => setCopied(false), 300);
76
78
  }
77
79
  catch (reason) {
78
80
  if (mounted.current) {
79
- setAnnouncement("Could not copy selected cells");
81
+ setAnnouncement(t("copyError"));
80
82
  onCopyError?.(reason);
81
83
  }
82
84
  }
@@ -97,10 +99,12 @@ export function useTableInteraction({ table, pinningActive, container, queryKey,
97
99
  const endWidth = !pinningActive
98
100
  ? 0
99
101
  : table.getEndVisibleLeafColumns().reduce((sum, col) => sum + col.getSize(), 0);
100
- if (box.left < viewport.left + startWidth)
101
- container.current.scrollLeft += box.left - viewport.left - startWidth;
102
- else if (box.right > viewport.right - endWidth)
103
- container.current.scrollLeft += box.right - viewport.right + endWidth;
102
+ const leftWidth = readingDirection === "rtl" ? endWidth : startWidth;
103
+ const rightWidth = readingDirection === "rtl" ? startWidth : endWidth;
104
+ if (box.left < viewport.left + leftWidth)
105
+ container.current.scrollLeft += box.left - viewport.left - leftWidth;
106
+ else if (box.right > viewport.right - rightWidth)
107
+ container.current.scrollLeft += box.right - viewport.right + rightWidth;
104
108
  }
105
109
  });
106
110
  }
@@ -129,8 +133,8 @@ export function useTableInteraction({ table, pinningActive, container, queryKey,
129
133
  const directions = {
130
134
  ArrowUp: "up",
131
135
  ArrowDown: "down",
132
- ArrowLeft: "left",
133
- ArrowRight: "right",
136
+ ArrowLeft: readingDirection === "rtl" ? "right" : "left",
137
+ ArrowRight: readingDirection === "rtl" ? "left" : "right",
134
138
  };
135
139
  const direction = directions[event.key];
136
140
  if (direction) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mendylanda/ui",
3
- "version": "0.3.2-dev.56.581b055ea0a9",
3
+ "version": "0.3.2-dev.58.0ef9785a4046",
4
4
  "description": "Mendy Landa’s reusable React components. Typed filters and tables with shared interaction behavior and customizable UI.",
5
5
  "homepage": "https://ui.mendylanda.com",
6
6
  "license": "MIT",
@@ -66,6 +66,11 @@
66
66
  "types": "./dist/table/index.d.ts",
67
67
  "import": "./dist/table/index.js",
68
68
  "default": "./dist/table/index.js"
69
+ },
70
+ "./locales/*": {
71
+ "types": "./dist/locales/*.d.ts",
72
+ "import": "./dist/locales/*.js",
73
+ "default": "./dist/locales/*.js"
69
74
  }
70
75
  },
71
76
  "publishConfig": {
@@ -74,6 +79,7 @@
74
79
  "dependencies": {
75
80
  "@hello-pangea/dnd": "18.0.1",
76
81
  "@radix-ui/react-checkbox": "^1.3.3",
82
+ "@radix-ui/react-direction": "^1.1.4",
77
83
  "@radix-ui/react-dropdown-menu": "^2.1.16",
78
84
  "@radix-ui/react-label": "^2.1.7",
79
85
  "@radix-ui/react-popover": "1.1.15",
@@ -112,5 +118,5 @@
112
118
  "build": "tsc -p tsconfig.build.json && node scripts/build-css.mjs",
113
119
  "typecheck": "tsc -p tsconfig.build.json --noEmit"
114
120
  },
115
- "gitHead": "581b055ea0a9ffef4ccf37d292ed5d74fbe8961c"
121
+ "gitHead": "0ef9785a4046cf8030396c3278c4231b866fcef4"
116
122
  }