@monolith-forensics/monolith-ui 1.7.1 → 1.8.1-dev.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.
Files changed (176) hide show
  1. package/dist/BarChart/BarChart.d.ts +3 -0
  2. package/dist/BarChart/BarChart.js +511 -0
  3. package/dist/BarChart/BarChart.lib.d.ts +31 -0
  4. package/dist/BarChart/BarChart.lib.js +136 -0
  5. package/dist/BarChart/BarChart.styled.d.ts +49 -0
  6. package/dist/BarChart/BarChart.styled.js +111 -0
  7. package/dist/BarChart/BarChart.types.d.ts +170 -0
  8. package/dist/BarChart/BarChart.types.js +1 -0
  9. package/dist/BarChart/index.d.ts +3 -0
  10. package/dist/BarChart/index.js +2 -0
  11. package/dist/Button/Button.js +9 -58
  12. package/dist/Calendar/Calendar.d.ts +3 -1
  13. package/dist/Calendar/Calendar.js +134 -33
  14. package/dist/Calendar/CalendarStyles.d.ts +3 -0
  15. package/dist/Calendar/CalendarStyles.js +92 -14
  16. package/dist/Calendar/calendarHelpers.d.ts +5 -1
  17. package/dist/Calendar/calendarHelpers.js +13 -5
  18. package/dist/ChartPrimitives/chartLegend.styled.d.ts +12 -0
  19. package/dist/ChartPrimitives/chartLegend.styled.js +52 -0
  20. package/dist/ChartPrimitives/chartTooltip.styled.d.ts +19 -0
  21. package/dist/ChartPrimitives/chartTooltip.styled.js +61 -0
  22. package/dist/ChartPrimitives/index.d.ts +2 -0
  23. package/dist/ChartPrimitives/index.js +2 -0
  24. package/dist/ChartUtils/chartColors.d.ts +8 -0
  25. package/dist/ChartUtils/chartColors.js +65 -0
  26. package/dist/ChartUtils/chartMath.d.ts +3 -0
  27. package/dist/ChartUtils/chartMath.js +3 -0
  28. package/dist/ChartUtils/index.d.ts +2 -0
  29. package/dist/ChartUtils/index.js +2 -0
  30. package/dist/Charts/BarChart/BarChart.d.ts +5 -0
  31. package/dist/Charts/BarChart/BarChart.js +549 -0
  32. package/dist/Charts/BarChart/BarChart.lib.d.ts +31 -0
  33. package/dist/Charts/BarChart/BarChart.lib.js +136 -0
  34. package/dist/Charts/BarChart/BarChart.styled.d.ts +51 -0
  35. package/dist/Charts/BarChart/BarChart.styled.js +115 -0
  36. package/dist/Charts/BarChart/BarChart.types.d.ts +171 -0
  37. package/dist/Charts/BarChart/BarChart.types.js +1 -0
  38. package/dist/Charts/BarChart/index.d.ts +3 -0
  39. package/dist/Charts/BarChart/index.js +2 -0
  40. package/dist/Charts/ChartPrimitives/ChartExportControl.d.ts +11 -0
  41. package/dist/Charts/ChartPrimitives/ChartExportControl.js +29 -0
  42. package/dist/Charts/ChartPrimitives/chartActions.styled.d.ts +1 -0
  43. package/dist/Charts/ChartPrimitives/chartActions.styled.js +8 -0
  44. package/dist/Charts/ChartPrimitives/chartLegend.styled.d.ts +12 -0
  45. package/dist/Charts/ChartPrimitives/chartLegend.styled.js +52 -0
  46. package/dist/Charts/ChartPrimitives/chartTooltip.styled.d.ts +19 -0
  47. package/dist/Charts/ChartPrimitives/chartTooltip.styled.js +61 -0
  48. package/dist/Charts/ChartPrimitives/index.d.ts +4 -0
  49. package/dist/Charts/ChartPrimitives/index.js +4 -0
  50. package/dist/Charts/ChartUtils/chartColors.d.ts +8 -0
  51. package/dist/Charts/ChartUtils/chartColors.js +65 -0
  52. package/dist/Charts/ChartUtils/chartExport.d.ts +47 -0
  53. package/dist/Charts/ChartUtils/chartExport.js +311 -0
  54. package/dist/Charts/ChartUtils/chartMath.d.ts +3 -0
  55. package/dist/Charts/ChartUtils/chartMath.js +3 -0
  56. package/dist/Charts/ChartUtils/index.d.ts +3 -0
  57. package/dist/Charts/ChartUtils/index.js +3 -0
  58. package/dist/Charts/HeatMap/HeatMap.d.ts +5 -0
  59. package/dist/Charts/HeatMap/HeatMap.js +212 -0
  60. package/dist/Charts/HeatMap/HeatMap.lib.d.ts +30 -0
  61. package/dist/Charts/HeatMap/HeatMap.lib.js +115 -0
  62. package/dist/Charts/HeatMap/HeatMap.styled.d.ts +37 -0
  63. package/dist/Charts/HeatMap/HeatMap.styled.js +91 -0
  64. package/dist/Charts/HeatMap/HeatMap.types.d.ts +80 -0
  65. package/dist/Charts/HeatMap/HeatMap.types.js +1 -0
  66. package/dist/Charts/HeatMap/index.d.ts +3 -0
  67. package/dist/Charts/HeatMap/index.js +2 -0
  68. package/dist/Charts/LineChart/LineChart.d.ts +5 -0
  69. package/dist/Charts/LineChart/LineChart.js +529 -0
  70. package/dist/Charts/LineChart/LineChart.lib.d.ts +24 -0
  71. package/dist/Charts/LineChart/LineChart.lib.js +132 -0
  72. package/dist/Charts/LineChart/LineChart.styled.d.ts +59 -0
  73. package/dist/Charts/LineChart/LineChart.styled.js +147 -0
  74. package/dist/Charts/LineChart/LineChart.types.d.ts +193 -0
  75. package/dist/Charts/LineChart/LineChart.types.js +1 -0
  76. package/dist/Charts/LineChart/index.d.ts +3 -0
  77. package/dist/Charts/LineChart/index.js +2 -0
  78. package/dist/Charts/PieChart/PieChart.d.ts +4 -0
  79. package/dist/Charts/PieChart/PieChart.js +199 -0
  80. package/dist/Charts/PieChart/PieChart.lib.d.ts +5 -0
  81. package/dist/Charts/PieChart/PieChart.lib.js +19 -0
  82. package/dist/Charts/PieChart/PieChart.styled.d.ts +51 -0
  83. package/dist/Charts/PieChart/PieChart.styled.js +163 -0
  84. package/dist/Charts/PieChart/PieChart.types.d.ts +100 -0
  85. package/dist/Charts/PieChart/PieChart.types.js +1 -0
  86. package/dist/Charts/PieChart/index.d.ts +2 -0
  87. package/dist/Charts/PieChart/index.js +1 -0
  88. package/dist/Charts/index.d.ts +5 -0
  89. package/dist/Charts/index.js +4 -0
  90. package/dist/CheckBox/CheckBox.js +2 -16
  91. package/dist/DateInput/DateInput.js +198 -143
  92. package/dist/DropDownMenu/components/MenuComponent.js +2 -1
  93. package/dist/DropDownMenu/components/MenuItem.js +5 -14
  94. package/dist/DropDownMenu/components/MenuItemList.js +7 -24
  95. package/dist/DropDownMenu/components/StyledFloatContainer.js +1 -1
  96. package/dist/FieldLabel/FieldLabel.js +4 -12
  97. package/dist/FileInputField/FileInputField.js +4 -23
  98. package/dist/FormSection/FormSection.js +5 -25
  99. package/dist/HeatMap/HeatMap.d.ts +3 -0
  100. package/dist/HeatMap/HeatMap.js +174 -0
  101. package/dist/HeatMap/HeatMap.lib.d.ts +30 -0
  102. package/dist/HeatMap/HeatMap.lib.js +115 -0
  103. package/dist/HeatMap/HeatMap.styled.d.ts +34 -0
  104. package/dist/HeatMap/HeatMap.styled.js +83 -0
  105. package/dist/HeatMap/HeatMap.types.d.ts +79 -0
  106. package/dist/HeatMap/HeatMap.types.js +1 -0
  107. package/dist/HeatMap/index.d.ts +3 -0
  108. package/dist/HeatMap/index.js +2 -0
  109. package/dist/IconButton/IconButton.js +2 -16
  110. package/dist/Input/Input.js +7 -56
  111. package/dist/LineChart/LineChart.d.ts +3 -0
  112. package/dist/LineChart/LineChart.js +491 -0
  113. package/dist/LineChart/LineChart.lib.d.ts +24 -0
  114. package/dist/LineChart/LineChart.lib.js +132 -0
  115. package/dist/LineChart/LineChart.styled.d.ts +57 -0
  116. package/dist/LineChart/LineChart.styled.js +150 -0
  117. package/dist/LineChart/LineChart.types.d.ts +192 -0
  118. package/dist/LineChart/LineChart.types.js +1 -0
  119. package/dist/LineChart/index.d.ts +3 -0
  120. package/dist/LineChart/index.js +2 -0
  121. package/dist/PieChart/PieChart.d.ts +2 -0
  122. package/dist/PieChart/PieChart.js +161 -0
  123. package/dist/PieChart/PieChart.lib.d.ts +5 -0
  124. package/dist/PieChart/PieChart.lib.js +19 -0
  125. package/dist/PieChart/PieChart.styled.d.ts +49 -0
  126. package/dist/PieChart/PieChart.styled.js +161 -0
  127. package/dist/PieChart/PieChart.types.d.ts +99 -0
  128. package/dist/PieChart/PieChart.types.js +1 -0
  129. package/dist/PieChart/index.d.ts +2 -0
  130. package/dist/PieChart/index.js +1 -0
  131. package/dist/Pill/Pill.js +8 -79
  132. package/dist/Popover/Popover.context.d.ts +2 -1
  133. package/dist/Popover/Popover.js +5 -2
  134. package/dist/Popover/Popover.styles.d.ts +1 -6
  135. package/dist/Popover/Popover.styles.js +11 -28
  136. package/dist/Popover/Popover.transitions.d.ts +4 -2
  137. package/dist/Popover/Popover.transitions.js +23 -49
  138. package/dist/Popover/PopoverDropdown.js +6 -8
  139. package/dist/Popover/PopoverTarget.js +6 -3
  140. package/dist/SegmentedControl/SegmentedControl.utils.d.ts +2 -2
  141. package/dist/SegmentedControl/SegmentedControl.utils.js +3 -30
  142. package/dist/SelectBox/SelectBox.js +3 -3
  143. package/dist/SelectBox/select-box.styled-components.d.ts +3 -1
  144. package/dist/SelectBox/select-box.styled-components.js +10 -48
  145. package/dist/SuperDatePicker/SuperDatePicker.d.ts +74 -0
  146. package/dist/SuperDatePicker/SuperDatePicker.js +557 -0
  147. package/dist/SuperDatePicker/index.d.ts +2 -0
  148. package/dist/SuperDatePicker/index.js +2 -0
  149. package/dist/Switch/Switch.d.ts +2 -2
  150. package/dist/Switch/Switch.js +18 -83
  151. package/dist/Table/StateStorage.d.ts +4 -0
  152. package/dist/Table/StateStorage.js +13 -0
  153. package/dist/Table/Table.js +160 -12
  154. package/dist/Table/TableComponents.d.ts +10 -0
  155. package/dist/Table/TableComponents.js +57 -0
  156. package/dist/Table/TableDefaults.d.ts +7 -0
  157. package/dist/Table/TableDefaults.js +7 -0
  158. package/dist/Table/TableProvider.js +263 -71
  159. package/dist/Table/TableRow.js +15 -10
  160. package/dist/Table/types.d.ts +64 -0
  161. package/dist/Tabs/Tab.js +8 -0
  162. package/dist/TagBox/TagBox.js +18 -76
  163. package/dist/TextArea/TextArea.js +4 -23
  164. package/dist/TextInput/TextInput.js +12 -6
  165. package/dist/Utilities/parseTimestamp.js +11 -6
  166. package/dist/core/ArrowButton.d.ts +2 -0
  167. package/dist/core/ArrowButton.js +7 -3
  168. package/dist/core/ClearButton.d.ts +2 -0
  169. package/dist/core/ClearButton.js +7 -3
  170. package/dist/core/controlSizes.d.ts +34 -0
  171. package/dist/core/controlSizes.js +190 -0
  172. package/dist/core/index.d.ts +1 -0
  173. package/dist/core/index.js +1 -0
  174. package/dist/index.d.ts +1 -0
  175. package/dist/index.js +1 -0
  176. package/package.json +5 -1
@@ -29,6 +29,27 @@ import { SelectionStatus } from "./enums";
29
29
  import moment from "moment";
30
30
  import { useControlled } from "../Utilities";
31
31
  import { exportTableToExcel } from "./Utils";
32
+ const RESERVED_FIELDS = [
33
+ "__key",
34
+ "__index",
35
+ "__level",
36
+ "__parentKey",
37
+ "__hasChildren",
38
+ "__childKeys",
39
+ ];
40
+ const EMPTY_TREE_META = {
41
+ parentKeyMap: new Map(),
42
+ childrenKeyMap: new Map(),
43
+ expandableKeys: [],
44
+ };
45
+ const DEFAULT_TREE_OPTIONS = {
46
+ enabled: false,
47
+ mode: "nested",
48
+ childrenField: "children",
49
+ parentIdField: "parentId",
50
+ indentPx: 16,
51
+ autoExpandOnMatch: true,
52
+ };
32
53
  const calculateSelectionTotal = (selectionState, totalRecords, dataLength = 0) => {
33
54
  if (!selectionState) {
34
55
  return 0;
@@ -48,11 +69,21 @@ const calculateSelectionTotal = (selectionState, totalRecords, dataLength = 0) =
48
69
  };
49
70
  export const TableContext = createContext(null);
50
71
  const TableProvider = (_a) => {
51
- var { children, columns, data, keyField, tableInstanceRef, stateStorage, tableMenuOptions, manualSorting, manualFiltering, manualSearch, manualExport, height, maxHeight, minHeight, focusedRowId, enableColumnResize, enableSorting, compact, totalRecords, onColumnStateChange, onColumnReorder, onColumnHeaderClick, onSort, onRowUpdated, tableElement, headerRowElm, tableDimensions, targetElm, listElm, defaultSelectionState, selectionState, onSelectionChange, defaultFilterState, filterState, onFilterChange } = _a, props = __rest(_a, ["children", "columns", "data", "keyField", "tableInstanceRef", "stateStorage", "tableMenuOptions", "manualSorting", "manualFiltering", "manualSearch", "manualExport", "height", "maxHeight", "minHeight", "focusedRowId", "enableColumnResize", "enableSorting", "compact", "totalRecords", "onColumnStateChange", "onColumnReorder", "onColumnHeaderClick", "onSort", "onRowUpdated", "tableElement", "headerRowElm", "tableDimensions", "targetElm", "listElm", "defaultSelectionState", "selectionState", "onSelectionChange", "defaultFilterState", "filterState", "onFilterChange"]);
72
+ var { children, columns, data, keyField, tableInstanceRef, stateStorage, tableMenuOptions, manualSorting, manualFiltering, manualSearch, manualExport, height, maxHeight, minHeight, focusedRowId, enableColumnResize, enableSorting, compact, totalRecords, onColumnStateChange, onColumnReorder, onColumnHeaderClick, onSort, onRowUpdated, tableElement, headerRowElm, tableDimensions, targetElm, listElm, defaultSelectionState, selectionState, onSelectionChange, defaultFilterState, filterState, onFilterChange, treeOptions, treeMeta, defaultExpandedKeys, expandedKeys, onExpandedChange } = _a, props = __rest(_a, ["children", "columns", "data", "keyField", "tableInstanceRef", "stateStorage", "tableMenuOptions", "manualSorting", "manualFiltering", "manualSearch", "manualExport", "height", "maxHeight", "minHeight", "focusedRowId", "enableColumnResize", "enableSorting", "compact", "totalRecords", "onColumnStateChange", "onColumnReorder", "onColumnHeaderClick", "onSort", "onRowUpdated", "tableElement", "headerRowElm", "tableDimensions", "targetElm", "listElm", "defaultSelectionState", "selectionState", "onSelectionChange", "defaultFilterState", "filterState", "onFilterChange", "treeOptions", "treeMeta", "defaultExpandedKeys", "expandedKeys", "onExpandedChange"]);
73
+ const _treeOptions = treeOptions || DEFAULT_TREE_OPTIONS;
74
+ const _treeMeta = treeMeta || EMPTY_TREE_META;
75
+ if (_treeOptions.enabled) {
76
+ if (RESERVED_FIELDS.includes(_treeOptions.childrenField)) {
77
+ throw new Error(`treeOptions.childrenField cannot be a reserved internal field: "${_treeOptions.childrenField}".`);
78
+ }
79
+ if (RESERVED_FIELDS.includes(_treeOptions.parentIdField)) {
80
+ throw new Error(`treeOptions.parentIdField cannot be a reserved internal field: "${_treeOptions.parentIdField}".`);
81
+ }
82
+ }
52
83
  const _columns = useMemo(() => columns
53
84
  .map((child, index) => {
54
- if (child.dataField === "__key") {
55
- throw new Error("dataField cannot be __key");
85
+ if (RESERVED_FIELDS.includes(child.dataField)) {
86
+ throw new Error(`dataField cannot be a reserved internal field: "${child.dataField}". Reserved: ${RESERVED_FIELDS.join(", ")}`);
56
87
  }
57
88
  // check for duplicate dataFields
58
89
  const dataFieldCount = columns.filter((col) => col.dataField === child.dataField).length;
@@ -71,7 +102,7 @@ const TableProvider = (_a) => {
71
102
  ? StateStorage.getTableState(stateStorage.key)
72
103
  : undefined;
73
104
  }, [stateStorage === null || stateStorage === void 0 ? void 0 : stateStorage.key]);
74
- const { columnState: savedColumnState, selectionState: savedSelectionState, sortState: savedSortState, searchState: savedSearchState, filterState: savedFilterState, } = savedTableState || {};
105
+ const { columnState: savedColumnState, selectionState: savedSelectionState, sortState: savedSortState, searchState: savedSearchState, filterState: savedFilterState, expandedKeys: savedExpandedKeys, } = savedTableState || {};
75
106
  const [compactState, setCompactState] = useState(compact || false);
76
107
  const [columnState, _setColumnState] = useState(syncColumnState(_columns, savedColumnState));
77
108
  const columnStateRef = useRef(columnState);
@@ -85,6 +116,8 @@ const TableProvider = (_a) => {
85
116
  rules: [],
86
117
  });
87
118
  const [sortState, setSortState] = useState(savedSortState);
119
+ const [_expandedKeys, _setExpandedKeys] = useControlled(expandedKeys, defaultExpandedKeys || savedExpandedKeys || []);
120
+ const expandedKeysSet = useMemo(() => new Set(_expandedKeys), [_expandedKeys]);
88
121
  const [_selectionState, _setSelectionState] = useControlled(selectionState, defaultSelectionState || {
89
122
  selectedRowKeys: (savedSelectionState === null || savedSelectionState === void 0 ? void 0 : savedSelectionState.selectedRowKeys) || [],
90
123
  excludedRowKeys: (savedSelectionState === null || savedSelectionState === void 0 ? void 0 : savedSelectionState.excludedRowKeys) || [],
@@ -238,58 +271,99 @@ const TableProvider = (_a) => {
238
271
  }
239
272
  }
240
273
  };
241
- const sortData = (sortState) => {
242
- // sort data
243
- return data.sort((a, b) => {
244
- if (sortState) {
245
- const aValue = a[sortState.dataField];
246
- const bValue = b[sortState.dataField];
247
- const aIsEmpty = aValue === null || aValue === undefined;
248
- const bIsEmpty = bValue === null || bValue === undefined;
249
- // Treat empty values as the smallest values.
250
- if (aIsEmpty && bIsEmpty) {
251
- return 0;
252
- }
253
- if (aIsEmpty || bIsEmpty) {
254
- if (sortState.dir === "asc") {
255
- return aIsEmpty ? -1 : 1;
256
- }
257
- if (sortState.dir === "desc") {
258
- return aIsEmpty ? 1 : -1;
259
- }
260
- }
274
+ const compareRows = (a, b, sortState) => {
275
+ if (sortState) {
276
+ const aValue = a[sortState.dataField];
277
+ const bValue = b[sortState.dataField];
278
+ const aIsEmpty = aValue === null || aValue === undefined;
279
+ const bIsEmpty = bValue === null || bValue === undefined;
280
+ // Treat empty values as the smallest values.
281
+ if (aIsEmpty && bIsEmpty) {
282
+ return 0;
283
+ }
284
+ if (aIsEmpty || bIsEmpty) {
261
285
  if (sortState.dir === "asc") {
262
- if (aValue < bValue) {
263
- return -1;
264
- }
265
- if (aValue > bValue) {
266
- return 1;
267
- }
268
- return 0;
286
+ return aIsEmpty ? -1 : 1;
269
287
  }
270
- else if (sortState.dir === "desc") {
271
- if (aValue > bValue) {
272
- return -1;
273
- }
274
- if (aValue < bValue) {
275
- return 1;
276
- }
277
- return 0;
288
+ if (sortState.dir === "desc") {
289
+ return aIsEmpty ? 1 : -1;
278
290
  }
279
291
  }
280
- // sort by __index
281
- if (a.__index < b.__index) {
282
- return -1;
292
+ if (sortState.dir === "asc") {
293
+ if (aValue < bValue)
294
+ return -1;
295
+ if (aValue > bValue)
296
+ return 1;
297
+ return 0;
283
298
  }
284
- if (a.__index > b.__index) {
285
- return 1;
299
+ else if (sortState.dir === "desc") {
300
+ if (aValue > bValue)
301
+ return -1;
302
+ if (aValue < bValue)
303
+ return 1;
304
+ return 0;
286
305
  }
287
- return 0;
288
- });
306
+ }
307
+ // sort by __index
308
+ if (a.__index < b.__index)
309
+ return -1;
310
+ if (a.__index > b.__index)
311
+ return 1;
312
+ return 0;
313
+ };
314
+ const sortData = (sortState) => {
315
+ if (!_treeOptions.enabled) {
316
+ // Flat data — sort in-place (preserves existing behavior).
317
+ return data.sort((a, b) => compareRows(a, b, sortState));
318
+ }
319
+ // Tree-aware sort: sort siblings only, then re-DFS to rebuild the
320
+ // flat order. Cross-parent sorting is never allowed in tree mode.
321
+ const byKey = new Map();
322
+ const childrenByParent = new Map();
323
+ for (const row of data) {
324
+ byKey.set(row.__key, row);
325
+ const pk = row.__parentKey;
326
+ if (!childrenByParent.has(pk))
327
+ childrenByParent.set(pk, []);
328
+ childrenByParent.get(pk).push(row);
329
+ }
330
+ for (const [, siblings] of childrenByParent) {
331
+ siblings.sort((a, b) => compareRows(a, b, sortState));
332
+ }
333
+ const result = [];
334
+ const walk = (parentKey) => {
335
+ const siblings = childrenByParent.get(parentKey);
336
+ if (!siblings)
337
+ return;
338
+ for (const row of siblings) {
339
+ result.push(row);
340
+ if (row.__hasChildren)
341
+ walk(row.__key);
342
+ }
343
+ };
344
+ walk(undefined);
345
+ return result;
346
+ };
347
+ const collectAncestors = (rows) => {
348
+ const ancestorSet = new Set();
349
+ const byKey = new Map();
350
+ for (const r of data)
351
+ byKey.set(r.__key, r);
352
+ for (const row of rows) {
353
+ let parentKey = row.__parentKey;
354
+ while (parentKey) {
355
+ if (ancestorSet.has(parentKey))
356
+ break;
357
+ ancestorSet.add(parentKey);
358
+ const parent = byKey.get(parentKey);
359
+ parentKey = parent === null || parent === void 0 ? void 0 : parent.__parentKey;
360
+ }
361
+ }
362
+ return ancestorSet;
289
363
  };
290
- const searchData = (searchText) => {
364
+ const searchData = (rows, searchText) => {
291
365
  const columnKeys = columnState.map((col) => col.dataField);
292
- return data.filter((row) => {
366
+ const matched = rows.filter((row) => {
293
367
  return columnKeys.some((key) => {
294
368
  if (typeof row[key] === "string") {
295
369
  return row[key].toLowerCase().includes(searchText.toLowerCase());
@@ -297,6 +371,16 @@ const TableProvider = (_a) => {
297
371
  return false;
298
372
  });
299
373
  });
374
+ if (!_treeOptions.enabled) {
375
+ return { rows: matched, ancestorKeys: new Set() };
376
+ }
377
+ const ancestorKeys = collectAncestors(matched);
378
+ const visibleSet = new Set(matched.map((r) => r.__key));
379
+ ancestorKeys.forEach((k) => visibleSet.add(k));
380
+ return {
381
+ rows: rows.filter((r) => visibleSet.has(r.__key)),
382
+ ancestorKeys,
383
+ };
300
384
  };
301
385
  const rowMatchesRule = (row, rule) => {
302
386
  var _a, _b, _c, _d;
@@ -396,16 +480,26 @@ const TableProvider = (_a) => {
396
480
  return true;
397
481
  }
398
482
  };
399
- const filterData = (filter) => {
400
- if (!data)
401
- return [];
483
+ const filterData = (rows, filter) => {
484
+ if (!rows)
485
+ return { rows: [], ancestorKeys: new Set() };
402
486
  const { combinator, rules } = filter;
403
- if (!combinator || !rules)
404
- return data;
405
- if (combinator === "or") {
406
- return data.filter((row) => rules.some((rule) => rowMatchesRule(row, rule)));
487
+ if (!combinator || !rules || rules.length === 0) {
488
+ return { rows, ancestorKeys: new Set() };
407
489
  }
408
- return data.filter((row) => rules.every((rule) => rowMatchesRule(row, rule)));
490
+ const matched = combinator === "or"
491
+ ? rows.filter((row) => rules.some((rule) => rowMatchesRule(row, rule)))
492
+ : rows.filter((row) => rules.every((rule) => rowMatchesRule(row, rule)));
493
+ if (!_treeOptions.enabled) {
494
+ return { rows: matched, ancestorKeys: new Set() };
495
+ }
496
+ const ancestorKeys = collectAncestors(matched);
497
+ const visibleSet = new Set(matched.map((r) => r.__key));
498
+ ancestorKeys.forEach((k) => visibleSet.add(k));
499
+ return {
500
+ rows: rows.filter((r) => visibleSet.has(r.__key)),
501
+ ancestorKeys,
502
+ };
409
503
  };
410
504
  const toggleColumnVisibility = (dataField) => {
411
505
  const newColumnState = columnState.map((col) => {
@@ -434,6 +528,47 @@ const TableProvider = (_a) => {
434
528
  const key = !!keyField ? row[keyField] : row.__key;
435
529
  return String(key);
436
530
  };
531
+ const firstVisibleDataField = useMemo(() => { var _a; return (_a = columnState.find((c) => c.visible !== false)) === null || _a === void 0 ? void 0 : _a.dataField; }, [columnState]);
532
+ const persistExpandedKeys = (next) => {
533
+ if ((stateStorage === null || stateStorage === void 0 ? void 0 : stateStorage.enabled) && (stateStorage === null || stateStorage === void 0 ? void 0 : stateStorage.type) === "localStorage") {
534
+ StateStorage.setExpandedKeys(stateStorage.key, next);
535
+ }
536
+ };
537
+ const updateExpandedKeys = (next) => {
538
+ _setExpandedKeys(next);
539
+ onExpandedChange === null || onExpandedChange === void 0 ? void 0 : onExpandedChange(next);
540
+ persistExpandedKeys(next);
541
+ };
542
+ const expandRow = (row) => {
543
+ var _a;
544
+ const key = (_a = row === null || row === void 0 ? void 0 : row.__key) !== null && _a !== void 0 ? _a : getRowKey(row);
545
+ if (expandedKeysSet.has(key))
546
+ return;
547
+ updateExpandedKeys([..._expandedKeys, key]);
548
+ };
549
+ const collapseRow = (row) => {
550
+ var _a;
551
+ const key = (_a = row === null || row === void 0 ? void 0 : row.__key) !== null && _a !== void 0 ? _a : getRowKey(row);
552
+ if (!expandedKeysSet.has(key))
553
+ return;
554
+ updateExpandedKeys(_expandedKeys.filter((k) => k !== key));
555
+ };
556
+ const toggleRowExpanded = (row) => {
557
+ var _a;
558
+ const key = (_a = row === null || row === void 0 ? void 0 : row.__key) !== null && _a !== void 0 ? _a : getRowKey(row);
559
+ if (expandedKeysSet.has(key)) {
560
+ updateExpandedKeys(_expandedKeys.filter((k) => k !== key));
561
+ }
562
+ else {
563
+ updateExpandedKeys([..._expandedKeys, key]);
564
+ }
565
+ };
566
+ const expandAllRows = () => {
567
+ updateExpandedKeys([..._treeMeta.expandableKeys]);
568
+ };
569
+ const collapseAllRows = () => {
570
+ updateExpandedKeys([]);
571
+ };
437
572
  const selectRow = (row) => {
438
573
  const key = getRowKey(row);
439
574
  const newSelectionState = {
@@ -571,6 +706,61 @@ const TableProvider = (_a) => {
571
706
  const key = getRowKey(row);
572
707
  return focusedRowId === key;
573
708
  };
709
+ const { _data, effectiveExpandedKeys } = useMemo(() => {
710
+ let processedData = data || [];
711
+ if (manualSorting !== true) {
712
+ processedData = sortData(sortState);
713
+ }
714
+ const autoExpandedSet = new Set();
715
+ if (manualFiltering !== true && _filterState) {
716
+ const result = filterData(processedData, _filterState);
717
+ processedData = result.rows;
718
+ if (_treeOptions.enabled && _treeOptions.autoExpandOnMatch) {
719
+ result.ancestorKeys.forEach((k) => autoExpandedSet.add(k));
720
+ }
721
+ }
722
+ if (manualSearch !== true && search) {
723
+ const result = searchData(processedData, search);
724
+ processedData = result.rows;
725
+ if (_treeOptions.enabled && _treeOptions.autoExpandOnMatch) {
726
+ result.ancestorKeys.forEach((k) => autoExpandedSet.add(k));
727
+ }
728
+ }
729
+ // Compute the effective expanded set: user expansion ∪ auto-expanded ancestors.
730
+ // Never mutates user's _expandedKeys.
731
+ const effective = new Set(expandedKeysSet);
732
+ autoExpandedSet.forEach((k) => effective.add(k));
733
+ // Final pass: drop rows whose ancestors are not in the effective set.
734
+ if (_treeOptions.enabled) {
735
+ const byKey = new Map();
736
+ for (const r of processedData)
737
+ byKey.set(r.__key, r);
738
+ processedData = processedData.filter((row) => {
739
+ let pk = row.__parentKey;
740
+ while (pk) {
741
+ if (!effective.has(pk))
742
+ return false;
743
+ const parent = byKey.get(pk);
744
+ pk = parent === null || parent === void 0 ? void 0 : parent.__parentKey;
745
+ }
746
+ return true;
747
+ });
748
+ }
749
+ return { _data: processedData, effectiveExpandedKeys: effective };
750
+ }, [
751
+ data,
752
+ columnState,
753
+ search,
754
+ sortState,
755
+ _filterState,
756
+ expandedKeysSet,
757
+ _treeOptions,
758
+ ]);
759
+ const isRowExpanded = (row) => {
760
+ var _a;
761
+ const key = (_a = row === null || row === void 0 ? void 0 : row.__key) !== null && _a !== void 0 ? _a : getRowKey(row);
762
+ return effectiveExpandedKeys.has(key);
763
+ };
574
764
  if (tableInstanceRef) {
575
765
  tableInstanceRef.current = {
576
766
  columnState,
@@ -587,6 +777,13 @@ const TableProvider = (_a) => {
587
777
  clearSelections,
588
778
  runSearch,
589
779
  clearSearch,
780
+ expandRow,
781
+ collapseRow,
782
+ toggleRowExpanded,
783
+ isRowExpanded,
784
+ expandAllRows,
785
+ collapseAllRows,
786
+ getExpandedRowKeys: () => [..._expandedKeys],
590
787
  getTableState: () => {
591
788
  return {
592
789
  columnState,
@@ -598,24 +795,12 @@ const TableProvider = (_a) => {
598
795
  },
599
796
  sortState,
600
797
  searchState: search,
601
- _filterState,
798
+ filterState: _filterState,
799
+ expandedKeys: [..._expandedKeys],
602
800
  };
603
801
  },
604
802
  };
605
803
  }
606
- const _data = useMemo(() => {
607
- let processedData = data; // create a new array to avoid mutating the original data
608
- if (manualSorting !== true) {
609
- processedData = sortData(sortState);
610
- }
611
- if (manualFiltering !== true && _filterState) {
612
- processedData = filterData(_filterState);
613
- }
614
- if (manualSearch !== true && search) {
615
- processedData = searchData(search);
616
- }
617
- return processedData;
618
- }, [data, columnState, search, sortState, _filterState]);
619
804
  return (_jsx(TableContext.Provider, { value: Object.assign({ columnState, setColumnState: updateColumnState, sortState, searchState: search, totalRecords,
620
805
  keyField,
621
806
  handleColumnReorder,
@@ -640,6 +825,13 @@ const TableProvider = (_a) => {
640
825
  stateStorage, tableHeight: height, tableMaxHeight: maxHeight, tableMinHeight: minHeight, compact, tableElement: tableElement, headerRowElm: headerRowElm, tableDimensions: tableDimensions, targetElm: targetElm, listElm: listElm, enableColumnResize,
641
826
  onSelectionChange,
642
827
  onColumnStateChange,
643
- onColumnReorder, onRowUpdated: onRowUpdated || (() => { }), tableMenuOptions, data: _data }, props), children: children }));
828
+ onColumnReorder, onRowUpdated: onRowUpdated || (() => { }), tableMenuOptions, data: _data, treeOptions: _treeOptions, firstVisibleDataField, expandedKeys: _expandedKeys, effectiveExpandedKeys,
829
+ isRowExpanded,
830
+ toggleRowExpanded,
831
+ expandRow,
832
+ collapseRow,
833
+ expandAllRows,
834
+ collapseAllRows,
835
+ onExpandedChange }, props), children: children }));
644
836
  };
645
837
  export default TableProvider;
@@ -1,20 +1,21 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Maximize2Icon } from "lucide-react";
2
+ import { ChevronRightIcon, Maximize2Icon } from "lucide-react";
3
3
  import ColumnResizer from "./ColumnResizer";
4
- import { InnerCellContent, TD, TR } from "./TableComponents";
4
+ import { InnerCellContent, TD, TR, TreeCellContent, TreeCellWrapper, TreeChevronButton, TreeChevronPlaceholder, TreeIndentSpacer, } from "./TableComponents";
5
5
  import useTable from "./useTable";
6
6
  import ActionCell from "./ActionCell";
7
7
  import ActionButton from "./ActionButton";
8
8
  import CheckBox from "../CheckBox";
9
9
  import { LoadingCellIndicator } from "./LoadingCellIndicator";
10
10
  const TableRow = ({ rowData, loading, rowStyle }) => {
11
- const { columnState, enableActionButton, onActionButtonClick, actionButtonIcon: Icon, enableSelection, selectRow, deselectRow, isRowSelected, isRowFocused, onRowUpdated, } = useTable();
11
+ const { columnState, enableActionButton, onActionButtonClick, actionButtonIcon: Icon, enableSelection, selectRow, deselectRow, isRowSelected, isRowFocused, onRowUpdated, treeOptions, firstVisibleDataField, isRowExpanded, toggleRowExpanded, } = useTable();
12
12
  const selected = isRowSelected(rowData);
13
13
  const focused = isRowFocused(rowData);
14
14
  const handleSelectionChange = (e) => {
15
15
  e === true ? selectRow(rowData) : deselectRow(rowData);
16
16
  };
17
17
  return (_jsxs(TR, { className: "mfui-tr", style: rowStyle, "data-key": rowData.__key, "data-selected": selected, "data-focused": focused, children: [enableSelection && (_jsx(ActionCell, { className: `mfui-td column-select`, children: _jsx(InnerCellContent, { className: "mfui inner-cell-content row-action row-selection-action", children: _jsx(CheckBox, { className: `mfui-checkbox`, value: selected, onChange: (e) => handleSelectionChange(e) }) }) })), enableActionButton && (_jsx(ActionCell, { className: `mfui-td column-action`, children: _jsx(InnerCellContent, { className: "mfui inner-cell-content row-action", children: _jsx(ActionButton, { variant: "subtle", onClick: () => onActionButtonClick === null || onActionButtonClick === void 0 ? void 0 : onActionButtonClick(rowData), children: Icon ? _jsx(Icon, { size: 14 }) : _jsx(Maximize2Icon, { size: 14 }) }) }) })), columnState.map((column, index) => {
18
+ var _a;
18
19
  if (column.visible === false)
19
20
  return null;
20
21
  if (loading) {
@@ -24,16 +25,20 @@ const TableRow = ({ rowData, loading, rowStyle }) => {
24
25
  flex: column.width ? "0 0 auto" : "1",
25
26
  }, children: _jsx(LoadingCellIndicator, {}) }, index));
26
27
  }
27
- return (_jsxs(TD, { className: `mfui-td column-${column.columnId}`, "data-field": column.dataField, style: {
28
+ const cellBody = column.render
29
+ ? column.render({ rowData, onRowUpdated })
30
+ : rowData[column.dataField];
31
+ const isTreeColumn = (treeOptions === null || treeOptions === void 0 ? void 0 : treeOptions.enabled) === true &&
32
+ column.dataField === firstVisibleDataField;
33
+ const expanded = isTreeColumn ? isRowExpanded(rowData) : false;
34
+ return (_jsxs(TD, { className: `mfui-td column-${column.columnId}`, "data-field": column.dataField, "data-tree-cell": isTreeColumn ? "true" : undefined, style: {
28
35
  width: column.width,
29
36
  minWidth: column.minWidth,
30
37
  flex: column.width ? "0 0 auto" : "1",
31
- }, children: [(column === null || column === void 0 ? void 0 : column.enableResize) === true && _jsx(ColumnResizer, { column: column }), _jsx(InnerCellContent, { className: "mfui inner-cell-content", children: column.render
32
- ? column.render({
33
- rowData,
34
- onRowUpdated,
35
- })
36
- : rowData[column.dataField] })] }, index));
38
+ }, children: [(column === null || column === void 0 ? void 0 : column.enableResize) === true && _jsx(ColumnResizer, { column: column }), _jsx(InnerCellContent, { className: "mfui inner-cell-content", children: isTreeColumn ? (_jsxs(TreeCellWrapper, { children: [_jsx(TreeIndentSpacer, { "$level": (_a = rowData.__level) !== null && _a !== void 0 ? _a : 0, "$indentPx": treeOptions.indentPx }), rowData.__hasChildren ? (_jsx(TreeChevronButton, { type: "button", "$expanded": expanded, onClick: (e) => {
39
+ e.stopPropagation();
40
+ toggleRowExpanded(rowData);
41
+ }, "aria-label": expanded ? "Collapse row" : "Expand row", "aria-expanded": expanded, children: _jsx(ChevronRightIcon, { size: 14 }) })) : (_jsx(TreeChevronPlaceholder, {})), _jsx(TreeCellContent, { children: cellBody })] })) : (cellBody) })] }, index));
37
42
  })] }));
38
43
  };
39
44
  export default TableRow;
@@ -10,6 +10,42 @@ export type StateStorage = {
10
10
  type: "localStorage";
11
11
  key: string;
12
12
  };
13
+ export type TreeMode = "nested" | "flat";
14
+ export type TreeOptions = {
15
+ /** Enable tree-row behavior. Default: false */
16
+ enabled?: boolean;
17
+ /** Input shape. Default: "nested" */
18
+ mode?: TreeMode;
19
+ /** For mode="nested": field name that holds child array. Default: "children" */
20
+ childrenField?: string;
21
+ /** For mode="flat": field name that holds parent id. Default: "parentId" */
22
+ parentIdField?: string;
23
+ /** For mode="flat": field name that holds the row's stable id. Falls back to keyField. */
24
+ idField?: string;
25
+ /** Pixel width of one indentation level. Default: 16 */
26
+ indentPx?: number;
27
+ /** If a descendant matches search/filter, auto-expand its ancestors for the effective view. Default: true */
28
+ autoExpandOnMatch?: boolean;
29
+ };
30
+ export type ResolvedTreeOptions = {
31
+ enabled: boolean;
32
+ mode: TreeMode;
33
+ childrenField: string;
34
+ parentIdField: string;
35
+ idField?: string;
36
+ indentPx: number;
37
+ autoExpandOnMatch: boolean;
38
+ };
39
+ export type ExpandedKeysState = string[];
40
+ export type OnExpandedChangeFn = (keys: string[]) => void;
41
+ export type TreeMeta = {
42
+ /** Map of row key -> parent row key (undefined for roots) */
43
+ parentKeyMap: Map<string, string | undefined>;
44
+ /** Map of parent key -> ordered list of direct child keys */
45
+ childrenKeyMap: Map<string | undefined, string[]>;
46
+ /** All row keys that have children (eligible for expansion) */
47
+ expandableKeys: string[];
48
+ };
13
49
  export type RenderOptions = {
14
50
  rowData: any;
15
51
  onRowUpdated?: (context: {
@@ -55,6 +91,7 @@ export type TableState = {
55
91
  sortState?: SortState;
56
92
  filterState?: Query;
57
93
  searchState?: string;
94
+ expandedKeys?: ExpandedKeysState;
58
95
  };
59
96
  export interface onResizeFinishedProps {
60
97
  column: ColumnState;
@@ -103,6 +140,17 @@ export type TableContextType = {
103
140
  data: any[];
104
141
  totalRecords?: number;
105
142
  keyField?: string;
143
+ treeOptions: ResolvedTreeOptions;
144
+ firstVisibleDataField?: string;
145
+ expandedKeys: string[];
146
+ effectiveExpandedKeys: Set<string>;
147
+ isRowExpanded: (row: any) => boolean;
148
+ toggleRowExpanded: (row: any) => void;
149
+ expandRow: (row: any) => void;
150
+ collapseRow: (row: any) => void;
151
+ expandAllRows: () => void;
152
+ collapseAllRows: () => void;
153
+ onExpandedChange?: OnExpandedChangeFn;
106
154
  tableHeight?: number;
107
155
  tableMaxHeight?: number;
108
156
  tableMinHeight?: number;
@@ -214,6 +262,11 @@ export interface TableProviderProps {
214
262
  defaultFilterState?: Query;
215
263
  filterState?: Query;
216
264
  onFilterChange?: (e: Query) => void;
265
+ treeOptions?: ResolvedTreeOptions;
266
+ defaultExpandedKeys?: ExpandedKeysState;
267
+ expandedKeys?: ExpandedKeysState;
268
+ onExpandedChange?: OnExpandedChangeFn;
269
+ treeMeta?: TreeMeta;
217
270
  }
218
271
  export interface TableRowProps {
219
272
  rowData: {
@@ -335,6 +388,10 @@ export interface TableProps {
335
388
  defaultFilterState?: Query;
336
389
  filterState?: Query;
337
390
  onFilterChange?: (e: Query) => void;
391
+ treeOptions?: TreeOptions;
392
+ defaultExpandedKeys?: ExpandedKeysState;
393
+ expandedKeys?: ExpandedKeysState;
394
+ onExpandedChange?: OnExpandedChangeFn;
338
395
  }
339
396
  export type TableInstance = {
340
397
  columnState: ColumnState[];
@@ -355,4 +412,11 @@ export type TableInstance = {
355
412
  clearSearch: () => void;
356
413
  clearSelections: () => void;
357
414
  getTableState: () => TableState;
415
+ expandRow: (row: any) => void;
416
+ collapseRow: (row: any) => void;
417
+ toggleRowExpanded: (row: any) => void;
418
+ isRowExpanded: (row: any) => boolean;
419
+ expandAllRows: () => void;
420
+ collapseAllRows: () => void;
421
+ getExpandedRowKeys: () => string[];
358
422
  };
package/dist/Tabs/Tab.js CHANGED
@@ -12,6 +12,14 @@ const StyledTabButton = styled(Button) `
12
12
  color: ${({ theme }) => theme.palette.text.secondary};
13
13
  font-weight: 500;
14
14
 
15
+ &:focus {
16
+ text-decoration: none;
17
+ }
18
+
19
+ &:focus-visible {
20
+ background-color: ${({ theme }) => theme.palette.action.hover};
21
+ }
22
+
15
23
  ${({ orientation }) => orientation === "horizontal" &&
16
24
  css `
17
25
  border-bottom: 2px solid transparent;