@ramesesinc/platform-core 0.1.9 → 0.1.10

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 (58) hide show
  1. package/dist/components/action/LookupPage.d.ts +2 -1
  2. package/dist/components/action/LookupPage.js +4 -3
  3. package/dist/components/action/Play.d.ts +6 -0
  4. package/dist/components/action/Play.js +40 -0
  5. package/dist/components/action/ProgressBar.d.ts +8 -0
  6. package/dist/components/action/ProgressBar.js +146 -0
  7. package/dist/components/action/ViewPage.d.ts +2 -1
  8. package/dist/components/action/ViewPage.js +19 -9
  9. package/dist/components/common/UIMenu.js +4 -3
  10. package/dist/components/index.d.ts +4 -1
  11. package/dist/components/index.js +4 -1
  12. package/dist/components/input/Combo.d.ts +21 -0
  13. package/dist/components/input/Combo.js +137 -0
  14. package/dist/components/input/DateField.js +7 -14
  15. package/dist/components/input/Text.d.ts +5 -0
  16. package/dist/components/input/Text.js +42 -7
  17. package/dist/components/list/EditableMenu.d.ts +2 -0
  18. package/dist/components/list/EditableMenu.js +128 -0
  19. package/dist/components/list/TabMenu.js +2 -2
  20. package/dist/components/list/TreeMenu.js +17 -12
  21. package/dist/components/table/DataList.d.ts +1 -1
  22. package/dist/components/table/DataList.js +49 -24
  23. package/dist/components/table/DataTable.d.ts +2 -0
  24. package/dist/components/table/DataTable.js +31 -22
  25. package/dist/components/view/FilterView.js +1 -1
  26. package/dist/components/view/HtmlForm.js +12 -9
  27. package/dist/components/view/PageView.js +36 -9
  28. package/dist/components/view/RootView.js +16 -16
  29. package/dist/core/AuthContext.js +1 -1
  30. package/dist/core/Page.js +2 -4
  31. package/dist/core/PageCache.d.ts +0 -2
  32. package/dist/core/PageCache.js +3 -8
  33. package/dist/core/PageContext.js +12 -0
  34. package/dist/core/PageViewContext.d.ts +8 -2
  35. package/dist/core/PageViewContext.js +129 -75
  36. package/dist/core/Panel.js +31 -9
  37. package/dist/index.css +79 -0
  38. package/dist/layouts/CardLayout.d.ts +2 -2
  39. package/dist/layouts/CardLayout.js +3 -4
  40. package/dist/layouts/HPanel.d.ts +2 -2
  41. package/dist/layouts/HPanel.js +1 -2
  42. package/dist/layouts/VPanel.d.ts +2 -2
  43. package/dist/layouts/VPanel.js +1 -2
  44. package/dist/layouts/index.d.ts +2 -3
  45. package/dist/layouts/index.js +2 -3
  46. package/dist/lib/utils/ExprUtil.js +18 -29
  47. package/dist/lib/utils/ResourceLoader.js +19 -7
  48. package/dist/lib/utils/SectionProvider.js +1 -1
  49. package/dist/lib/utils/initResourceLoader.d.ts +2 -0
  50. package/dist/lib/utils/initResourceLoader.js +64 -95
  51. package/dist/lib/utils/nunjucks.d.ts +2 -0
  52. package/dist/lib/utils/nunjucks.js +8 -0
  53. package/dist/templates/CrudFormTemplate.js +2 -3
  54. package/dist/templates/DataListTemplate.js +1 -1
  55. package/dist/templates/WizardTemplate.js +3 -1
  56. package/package.json +1 -1
  57. package/dist/components/input/Select.d.ts +0 -14
  58. package/dist/components/input/Select.js +0 -40
@@ -2,20 +2,38 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useRef, useState } from "react";
3
3
  import UIComponent from "../common/UIComponent";
4
4
  import useUIInput from "../common/UIInput";
5
+ class TextCaseFormatter {
6
+ apply(value, mode) {
7
+ switch (mode) {
8
+ case "upper":
9
+ return value.toUpperCase();
10
+ case "lower":
11
+ return value.toLowerCase();
12
+ case "capitalize":
13
+ return value.replace(/\b\w/g, (char) => char.toUpperCase());
14
+ case "none":
15
+ default:
16
+ return value;
17
+ }
18
+ }
19
+ }
20
+ export const applyTextCase = (value, mode) => {
21
+ return new TextCaseFormatter().apply(value, mode);
22
+ };
5
23
  const TextField = (props) => {
6
- const { name, immediate = true } = props !== null && props !== void 0 ? props : {};
7
- const [focused, setFocused] = useState(false);
24
+ var _a, _b;
25
+ const { immediate = true, align = "left", noSpace = false, required = false, placeholder } = props !== null && props !== void 0 ? props : {};
26
+ // const [focused, setFocused] = useState(false);
8
27
  const inputRef = useRef(null);
9
28
  const valueRef = useRef("");
10
- const className = "border rounded px-2 py-1 w-full";
11
29
  const handleFocus = () => {
12
- setFocused(true);
30
+ // setFocused(true);
13
31
  };
14
32
  const handleBlur = () => {
15
33
  if (!immediate) {
16
34
  setValue(inputValue);
17
35
  }
18
- setFocused(false);
36
+ // setFocused(false);
19
37
  };
20
38
  const onRefresh = () => {
21
39
  setInputValue(getValue());
@@ -25,7 +43,10 @@ const TextField = (props) => {
25
43
  const [inputValue, setInputValue] = useState(valueRef.current);
26
44
  const onChange = (e) => {
27
45
  var _a;
28
- const text = (_a = e.target.value) !== null && _a !== void 0 ? _a : "";
46
+ let text = (_a = e.target.value) !== null && _a !== void 0 ? _a : "";
47
+ if (noSpace) {
48
+ text = text.replace(/\s+/g, "");
49
+ }
29
50
  if (text !== inputValue) {
30
51
  valueRef.current = text;
31
52
  setInputValue(valueRef.current);
@@ -34,6 +55,20 @@ const TextField = (props) => {
34
55
  setValue(text);
35
56
  }
36
57
  };
37
- return (_jsx(UIComponent, Object.assign({}, (props !== null && props !== void 0 ? props : {}), { children: _jsx("input", { type: "text", ref: inputRef, onChange: onChange, value: inputValue, onFocus: handleFocus, onBlur: handleBlur, className: className }) })));
58
+ const handleKeyDown = (e) => {
59
+ if (noSpace && e.key === " ") {
60
+ e.preventDefault();
61
+ }
62
+ };
63
+ const alignClass = {
64
+ left: "text-left",
65
+ center: "text-center",
66
+ right: "text-right",
67
+ }[align];
68
+ const inReadMode = (_b = (_a = binding === null || binding === void 0 ? void 0 : binding.isReadMode) === null || _a === void 0 ? void 0 : _a.call(binding)) !== null && _b !== void 0 ? _b : false;
69
+ const defaultStyleClass = "text-sm px-2 py-2 border rounded-md shadow-sm transition-colors duration-150 ease-in-out w-full";
70
+ const focusStyleClass = `focus:outline-none ${inReadMode ? "bg-gray-50" : "focus:bg-yellow-50"} focus:ring-1 focus:ring-blue-400`;
71
+ const borderClass = "border-gray-300";
72
+ return (_jsx(UIComponent, Object.assign({}, (props !== null && props !== void 0 ? props : {}), { children: _jsx("input", { type: "text", ref: inputRef, onChange: onChange, onKeyDown: handleKeyDown, value: inputValue, onFocus: handleFocus, onBlur: handleBlur, required: required, disabled: inReadMode, placeholder: inReadMode ? "" : placeholder, className: `${defaultStyleClass} ${focusStyleClass} ${alignClass} ${borderClass}` }) })));
38
73
  };
39
74
  export default TextField;
@@ -0,0 +1,2 @@
1
+ declare const EditableMenu: (props: any) => import("react/jsx-runtime").JSX.Element;
2
+ export default EditableMenu;
@@ -0,0 +1,128 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { DataBindingProvider } from "@/core/DataContext";
3
+ import DynamicIcon from "@/core/DynamicIcon";
4
+ import { usePageContext } from "@/core/PageContext";
5
+ import { usePageViewContext } from "@/core/PageViewContext";
6
+ import useDependHandler from "@/core/UIDependHandler";
7
+ import { replaceValues } from "@/lib/utils/BeanUtils";
8
+ import { Eye } from "lucide-react";
9
+ import { useEffect, useRef, useState } from "react";
10
+ import ViewPage from "../action/ViewPage";
11
+ import useUIMenu from "../common/UIMenu";
12
+ const EditableMenu = (props) => {
13
+ const { name, depends, title, menugroup, items: itemsProp, data, addPage, viewPage } = props !== null && props !== void 0 ? props : {};
14
+ const [activeItem, setActiveItem] = useState(null);
15
+ const [resolvedData, setResolvedData] = useState(data);
16
+ const [sortedItems, setSortedItems] = useState([]);
17
+ const pageContext = usePageContext();
18
+ const pageView = usePageViewContext();
19
+ const uuid = Math.random().toString(36).slice(2);
20
+ const dragHandler = useDragHandler({
21
+ items: sortedItems,
22
+ onSort: setSortedItems,
23
+ onDrop: async (draggedItem, updatedItems) => {
24
+ const reordered = updatedItems.map((item, idx) => ({
25
+ id: item.id,
26
+ sortorder: idx + 1, // ← 1-based sortorder
27
+ }));
28
+ console.log("resolvedData", JSON.stringify(resolvedData, null, 2));
29
+ console.log("reordered", JSON.stringify(reordered, null, 2));
30
+ // const status = await pageContext?.postMgmt("menus", "reorder", {
31
+ // type: resolvedData?.params?.type,
32
+ // groupid: resolvedData?.params?.groupid,
33
+ // items: reordered,
34
+ // });
35
+ // console.log("status", status);
36
+ },
37
+ });
38
+ const { items } = useUIMenu({ menugroup, items: itemsProp, data: resolvedData });
39
+ const handleItemClick = (item) => {
40
+ // console.log("Item clicked:", item);
41
+ pageContext === null || pageContext === void 0 ? void 0 : pageContext.set(name, item);
42
+ setActiveItem(item);
43
+ };
44
+ const handleAdd = () => {
45
+ console.log("Add clicked", addPage);
46
+ const { url, mode } = addPage !== null && addPage !== void 0 ? addPage : {};
47
+ const idx = ["window", "popup"].indexOf(String(mode).toLowerCase());
48
+ console.log(idx);
49
+ if (idx >= 0) {
50
+ // pageView.setPage(url, { mode });
51
+ }
52
+ else {
53
+ // pageView.setSelectedPage(url);
54
+ pageContext.set(name, url);
55
+ }
56
+ };
57
+ const handleView = (item) => {
58
+ const { url, mode } = viewPage !== null && viewPage !== void 0 ? viewPage : {};
59
+ console.log("View clicked", url, mode, item);
60
+ };
61
+ const handleDelete = (item) => console.log("Delete clicked", item);
62
+ useEffect(() => {
63
+ if (items.length === 0)
64
+ return;
65
+ const firstItem = items[0];
66
+ setActiveItem(firstItem);
67
+ setSortedItems(items);
68
+ pageContext === null || pageContext === void 0 ? void 0 : pageContext.set(name, items[0]);
69
+ }, [items]);
70
+ const resolveData = () => {
71
+ var _a;
72
+ if (!(data === null || data === void 0 ? void 0 : data.params))
73
+ return data;
74
+ const dependsValue = (_a = pageContext === null || pageContext === void 0 ? void 0 : pageContext.get(depends)) !== null && _a !== void 0 ? _a : {};
75
+ const resolvedParams = replaceValues(data.params, dependsValue);
76
+ return Object.assign(Object.assign({}, data), { params: resolvedParams });
77
+ };
78
+ const onRefresh = () => {
79
+ // when depends changes → re-resolve params
80
+ setResolvedData(resolveData());
81
+ // setActiveItem(null); // reset active item
82
+ };
83
+ useDependHandler({ name: depends, onRefresh });
84
+ return (_jsxs("div", { className: "p-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("p", { className: "text-lg font-semibold", children: title }), _jsx(ViewPage, { url: addPage === null || addPage === void 0 ? void 0 : addPage.url, mode: addPage === null || addPage === void 0 ? void 0 : addPage.mode, iconOnly: true, icon: _jsx(DynamicIcon, { icon: "Plus", size: 18 }), title: title })] }), _jsx("div", { className: "border-b border-gray-200 my-2" }), _jsx("div", { className: "flex flex-col gap-2", children: sortedItems.map((item, index) => {
85
+ var _a;
86
+ const isActive = (activeItem === null || activeItem === void 0 ? void 0 : activeItem.id) === item.id; // ← use activeItem
87
+ return (_jsx(DataBindingProvider, { data: { data: item }, children: _jsxs("div", { draggable: true, onDragStart: () => dragHandler.handleDragStart(index), onDragOver: (e) => dragHandler.handleDragOver(e, index), onDrop: dragHandler.handleDrop, onDragEnd: dragHandler.handleDragEnd, className: `flex items-center justify-between border-b p-2 cursor-pointer transition-colors
88
+ ${isActive ? "bg-gray-200" : "bg-gray-50 border-gray-200 hover:bg-gray-200"}`, onClick: () => handleItemClick(item), children: [_jsx("span", { className: "text-gray-400 cursor-grab mr-2", children: _jsx(DynamicIcon, { icon: "GripVertical", size: 16 }) }), _jsx("span", { className: `text-base flex-1 ${isActive ? "font-medium" : ""}`, children: item.title }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(ViewPage, { url: viewPage === null || viewPage === void 0 ? void 0 : viewPage.url, mode: viewPage === null || viewPage === void 0 ? void 0 : viewPage.mode, popupClassName: viewPage === null || viewPage === void 0 ? void 0 : viewPage.popupClassName, iconOnly: true, icon: _jsx(Eye, { size: 16, color: "blue" }) }), renderButton((_a = item.deleteIcon) !== null && _a !== void 0 ? _a : "Trash", () => handleDelete(item), "text-red-500")] })] }) }, `${uuid}-${index}`));
89
+ }) })] }));
90
+ };
91
+ export default EditableMenu;
92
+ /* ------------------------------------------------------------------ */
93
+ /* Render Button */
94
+ /* ------------------------------------------------------------------ */
95
+ const renderButton = (icon, onClick, color = "text-gray-500") => (_jsx("span", { className: `${color} cursor-pointer hover:opacity-70 transition-opacity`, onClick: (e) => {
96
+ e.stopPropagation();
97
+ onClick();
98
+ }, children: _jsx(DynamicIcon, { icon: icon, size: 18 }) }));
99
+ const useDragHandler = ({ items, onSort, onDrop }) => {
100
+ const dragIndexRef = useRef(null);
101
+ const dragOverIndexRef = useRef(null);
102
+ const handleDragStart = (index) => {
103
+ dragIndexRef.current = index;
104
+ };
105
+ const handleDragOver = (e, index) => {
106
+ e.preventDefault();
107
+ dragOverIndexRef.current = index;
108
+ };
109
+ const handleDrop = () => {
110
+ const from = dragIndexRef.current;
111
+ const to = dragOverIndexRef.current;
112
+ if (from == null || to == null || from === to)
113
+ return;
114
+ const draggedItem = items[from];
115
+ const updated = [...items];
116
+ const [moved] = updated.splice(from, 1);
117
+ updated.splice(to, 0, moved);
118
+ onSort(updated);
119
+ onDrop === null || onDrop === void 0 ? void 0 : onDrop(draggedItem, updated);
120
+ dragIndexRef.current = null;
121
+ dragOverIndexRef.current = null;
122
+ };
123
+ const handleDragEnd = () => {
124
+ dragIndexRef.current = null;
125
+ dragOverIndexRef.current = null;
126
+ };
127
+ return { handleDragStart, handleDragOver, handleDrop, handleDragEnd };
128
+ };
@@ -4,8 +4,8 @@ import { useEffect, useState } from "react";
4
4
  import { usePageContext } from "../../core/PageContext";
5
5
  import { usePageViewContext } from "../../core/PageViewContext";
6
6
  import useDependHandler from "../../core/UIDependHandler";
7
- import HPanel from "../../layouts/HPanel";
8
- import VPanel from "../../layouts/VPanel";
7
+ import { HPanel } from "../../layouts/HPanel";
8
+ import { VPanel } from "../../layouts/VPanel";
9
9
  const TabMenu = (props) => {
10
10
  var _a;
11
11
  const { name, depends, items = [], data, menugroup, orientation = "horizontal" } = props !== null && props !== void 0 ? props : {};
@@ -84,6 +84,7 @@ const TreeMenu = (props) => {
84
84
  const [openGroups, setOpenGroups] = useState([]);
85
85
  const [activeItem, setActiveItem] = useState({});
86
86
  const [items, setItems] = useState([]);
87
+ const [hashPage, setHashPage] = useState(null);
87
88
  const initializedRef = useRef(false);
88
89
  const { items: rawItems } = useUIMenu({
89
90
  items: itemsProp,
@@ -95,7 +96,9 @@ const TreeMenu = (props) => {
95
96
  const { path = "" } = (_a = pageView.getOriginalLocationInfo()) !== null && _a !== void 0 ? _a : {};
96
97
  const [, ...anchors] = path.split("#");
97
98
  const [selectedPath] = anchors;
98
- pageContext.set(contextKey, selectedPath);
99
+ if (selectedPath) {
100
+ pageContext.set(contextKey, selectedPath);
101
+ }
99
102
  }, []);
100
103
  /* ---------------------- Sync active item from page view ---------------------- */
101
104
  useLayoutEffect(() => {
@@ -115,23 +118,27 @@ const TreeMenu = (props) => {
115
118
  }, [rawItems]);
116
119
  /* ---------------------- Auto-select first item on init ---------------------- */
117
120
  useEffect(() => {
121
+ var _a;
118
122
  if (initializedRef.current || items.length === 0)
119
123
  return;
120
124
  const firstItem = findFirstItem(items);
121
125
  if (!(firstItem === null || firstItem === void 0 ? void 0 : firstItem.page))
122
126
  return;
123
127
  let selectedPage = pageContext.get(contextKey);
124
- // console.log("treemenu selected page from context", contextKey, selectedPage);
125
- if (selectedPage == null && contextKey === "selectedPage") {
126
- selectedPage = pageView.getSelectedPage();
127
- // console.log("treemenu selected page fallback from context", contextKey, selectedPage);
128
+ if (selectedPage == null) {
129
+ // fallback to window.location.hash
130
+ const hash = (_a = window.location.hash) !== null && _a !== void 0 ? _a : "";
131
+ const [, firstAnchor] = hash.split("#");
132
+ if (firstAnchor) {
133
+ selectedPage = firstAnchor; // strip query params
134
+ setHashPage(selectedPage);
135
+ }
128
136
  }
129
- // console.log("treemenu selected page final", contextKey, selectedPage);
130
137
  if (selectedPage != null) {
131
138
  const selectedItem = findItemByPage(items, selectedPage);
132
- // console.log("treemenu findItemByPage", selectedPage, selectedItem);
133
139
  if (selectedItem) {
134
- setOpenGroups(findGroupPath(items, selectedPage));
140
+ const groupPath = findGroupPath(items, selectedPage);
141
+ setOpenGroups(groupPath);
135
142
  setActiveItem(selectedItem);
136
143
  }
137
144
  else {
@@ -144,7 +151,7 @@ const TreeMenu = (props) => {
144
151
  setActiveItem(firstItem);
145
152
  }
146
153
  initializedRef.current = true;
147
- }, [items, contextKey]);
154
+ }, [items, contextKey, hashPage]);
148
155
  /* ---------------------- Sync page context on active item change ---------------------- */
149
156
  useEffect(() => {
150
157
  const { mode, page } = (activeItem !== null && activeItem !== void 0 ? activeItem : {});
@@ -155,7 +162,6 @@ const TreeMenu = (props) => {
155
162
  pageView.setPage(page, { mode });
156
163
  }
157
164
  else {
158
- pageView.setSelectedPage(page);
159
165
  pageContext.set(contextKey, page);
160
166
  }
161
167
  }, [activeItem]);
@@ -182,8 +188,7 @@ const TreeMenu = (props) => {
182
188
  };
183
189
  /* ---------------------- Events ---------------------- */
184
190
  const handleSubItemClick = (item) => {
185
- if (!item.page || item.page === activeItem.page)
186
- return;
191
+ // if (!item.page || item.page === activeItem.page) return;
187
192
  setActiveItem(item);
188
193
  };
189
194
  /* ---------------------- Recursive render ---------------------- */
@@ -50,7 +50,7 @@ export interface DataListAttr {
50
50
  searchDebounce?: number;
51
51
  onSearchChange?: (text: string) => void;
52
52
  filters?: FilterDefinition[] | FilterDefinition[][];
53
- showFilterPanel?: boolean;
53
+ filterPage?: Record<string, any>;
54
54
  onFilterChange?: (filters: Record<string, any>) => void;
55
55
  sortable?: boolean;
56
56
  defaultSort?: {
@@ -10,8 +10,9 @@ var __rest = (this && this.__rest) || function (s, e) {
10
10
  return t;
11
11
  };
12
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
- import { Columns, Eye, RefreshCcw, Search, Trash } from "lucide-react";
14
- import { useCallback, useRef, useState } from "react";
13
+ import { Tooltip } from "@ramesesinc/client";
14
+ import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, Columns, Eye, Funnel, RefreshCcw, Search, Trash } from "lucide-react";
15
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
15
16
  import { useApp } from "../../core/AppContext";
16
17
  import { useDataContext } from "../../core/DataContext";
17
18
  import { DynamicComponent } from "../../core/DynamicComponent";
@@ -20,10 +21,12 @@ import Panel from "../../core/Panel";
20
21
  import useDependHandler from "../../core/UIDependHandler";
21
22
  import { replaceValues } from "../../lib/utils/BeanUtils";
22
23
  import { getUrlPageParams } from "../../lib/utils/PageUtils";
24
+ import LookupPage from "../action/LookupPage";
23
25
  import { DataTable } from "./DataTable";
24
26
  import ListHandler from "./ListHandler";
25
27
  import { TableProvider, useTableContext } from "./TableContext";
26
- const InnerDataList = ({ cols, emptyMessage = "No data available", errorMessage, striped = false, bordered = false, hover = true, dense = false, showPagination = true, paginationPosition = "bottom", showPageInfo = true, showTotalCount = true, showRowsPerPage = true, rowsPerPageOptions = [5, 10, 20, 50, 100], searchable = false, searchPlaceholder = "Search...", searchDebounce = 300, onSearchChange, filters = [], showFilterPanel = false, onFilterChange, sortable = true, showSortIndicator = true, selectable = false, selectionMode = "multiple", onSelectionChange, selectOnRowClick = false, onRowClick, rowActions = [], bulkActions = [], showBulkActions = true, toolbarActions = [], showToolbar = true, toolbarTitle, showRefreshButton = true, showExportButton = false, onLoad, onError, onRefresh, onExport, className = "", rowClassName, depends, handle, }) => {
28
+ const InnerDataList = ({ cols, emptyMessage = "No data available", errorMessage, striped = false, bordered = false, hover = true, dense = false, showPagination = true, paginationPosition = "bottom", showPageInfo = true, showTotalCount = true, showRowsPerPage = true, rowsPerPageOptions = [5, 10, 20, 50, 100], searchable = false, searchPlaceholder = "Search...", searchDebounce = 300, onSearchChange, filters = [], filterPage, onFilterChange, sortable = true, showSortIndicator = true, selectable = false, selectionMode = "multiple", onSelectionChange, selectOnRowClick = false, onRowClick, rowActions = [], bulkActions = [], showBulkActions = true, toolbarActions = [], showToolbar = true, toolbarTitle, showRefreshButton = true, showExportButton = false, onLoad, onError, onRefresh, onExport, className = "", rowClassName, depends, handle, }) => {
29
+ var _a;
27
30
  const { listHandler, columns, rows, setRows, loading: ctxLoading, setLoading } = useTableContext();
28
31
  // ============================================================================
29
32
  // STATE
@@ -215,15 +218,15 @@ const InnerDataList = ({ cols, emptyMessage = "No data available", errorMessage,
215
218
  // ============================================================================
216
219
  // DISPLAY COLUMNS — actions + sort indicators
217
220
  // ============================================================================
221
+ const actionUuid = useRef(Math.random().toString(36).slice(2));
218
222
  const renderActionCell = (row, rowIndex) => {
219
223
  const visible = rowActions.filter((a) => !a.show || a.show(row));
220
224
  if (visible.length === 0)
221
225
  return null;
222
- const uuid = Math.random().toString(36).slice(2);
223
226
  return (_jsx("div", { className: "dl-actions flex justify-center items-center", children: visible.map((action, i) => (_jsx("div", { children: _jsx(DynamicComponent, { config: {
224
227
  component: action.component,
225
228
  attr: Object.assign(Object.assign({}, action.attr), { opt: { data: row } }),
226
- } }) }, `${uuid}-${i}`))) }));
229
+ } }) }, `${actionUuid.current}-${i}`))) }));
227
230
  };
228
231
  const displayColumns = rowActions.length > 0 && visibleUserColumns.length > 0
229
232
  ? [
@@ -246,17 +249,24 @@ const InnerDataList = ({ cols, emptyMessage = "No data available", errorMessage,
246
249
  // ============================================================================
247
250
  // RENDER TOOLBAR
248
251
  // ============================================================================
252
+ const toolbarUuid = useRef(Math.random().toString(36).slice(2));
249
253
  const renderToolbar = () => {
250
254
  if (!showToolbar)
251
255
  return null;
252
- const uuid = Math.random().toString(36).slice(2);
253
256
  return (_jsxs("div", { className: "dl-toolbar", children: [_jsxs("div", { className: "dl-toolbar-left", children: [toolbarTitle && _jsx("h3", { className: "dl-toolbar-title", children: toolbarTitle }), _jsxs("div", { className: "dl-toolbar-right", children: [showBulkActions &&
254
257
  selectedRows.length > 0 &&
255
258
  bulkActions.map((action, i) => (_jsxs("button", { className: `dl-btn dl-btn-${action.variant || "default"}`, onClick: () => {
256
259
  const selectedData = rows.filter((row) => selectedRows.includes(row.id || JSON.stringify(row)));
257
260
  action.onClick(selectedData);
258
- }, children: [action.icon && _jsx("span", { children: action.icon }), action.label] }, action.label || i))), toolbarActions.map((action, i) => (_jsx("div", { children: _jsx(DynamicComponent, { config: { component: action.component, attr: action.attr || {} } }) }, `${uuid}-${i}`))), showExportButton && (_jsxs("button", { className: "dl-btn", onClick: onExport, children: [_jsx("span", { children: "\uD83D\uDCE5" }), " Export"] }))] })] }), _jsxs("div", { className: "flex items-center", children: [_jsx(RefreshButton, { show: showRefreshButton, onClick: handleRefresh }), _jsx(ColumnToggle, { columns: columns, hiddenColumns: hiddenColumns, setHiddenColumns: setHiddenColumns }), _jsx(SearchBox, { searchable: searchable, searchPlaceholder: searchPlaceholder, searchText: searchText, onSearch: handleSearch })] })] }));
261
+ }, children: [action.icon && _jsx("span", { children: action.icon }), action.label] }, action.label || i))), _jsx(SearchBox, { searchable: searchable, searchPlaceholder: searchPlaceholder, searchText: searchText, onSearch: handleSearch })] })] }), MemoizedToolbar] }));
259
262
  };
263
+ const handleRefreshRef = useRef(handleRefresh);
264
+ useEffect(() => {
265
+ handleRefreshRef.current = handleRefresh;
266
+ }, [handleRefresh]);
267
+ const MemoizedToolbar = useMemo(() => {
268
+ return (_jsxs("div", { className: "flex items-center gap-1", children: [toolbarActions.map((action, i) => (_jsx("div", { children: _jsx(DynamicComponent, { config: { component: action.component, attr: action.attr || {} } }) }, `${toolbarUuid.current}-${i}`))), _jsx(FilterButton, { filterPage: filterPage }), _jsx(RefreshButton, { show: showRefreshButton, onClick: handleRefresh }), _jsx(ColumnToggle, { columns: columns, hiddenColumns: hiddenColumns, setHiddenColumns: setHiddenColumns })] }));
269
+ }, [toolbarActions, filterPage, showRefreshButton, hiddenColumns, columns]);
260
270
  // ============================================================================
261
271
  // RENDER FILTER PANEL
262
272
  // ============================================================================
@@ -279,11 +289,11 @@ const InnerDataList = ({ cols, emptyMessage = "No data available", errorMessage,
279
289
  const hasPrev = listHandler.hasPrevPage();
280
290
  const startRecord = (currentPage - 1) * rowsPerPage + 1;
281
291
  const endRecord = Math.min(currentPage * rowsPerPage, totalRecords);
282
- return (_jsxs("div", { className: "dl-pagination", children: [_jsxs("div", { className: "dl-pagination-info", children: [showPageInfo && showTotalCount && (_jsxs("span", { children: ["Showing ", startRecord, "-", endRecord, " of ", totalRecords, " records"] })), showPageInfo && !showTotalCount && _jsxs("span", { children: ["Page ", currentPage] })] }), _jsxs("div", { className: "dl-pagination-controls", children: [showRowsPerPage && (_jsxs("div", { className: "dl-rows-per-page", children: [_jsx("span", { children: "Rows per page:" }), _jsx("select", { value: rowsPerPage, onChange: (e) => handleRowsPerPage(Number(e.target.value)), children: rowsPerPageOptions.map((o) => (_jsx("option", { value: o, children: o }, o))) })] })), _jsx("button", { className: "dl-page-btn", disabled: !hasPrev, onClick: handleFirstPage, children: "First" }), _jsx("button", { className: "dl-page-btn", disabled: !hasPrev, onClick: handlePrevPage, children: "\u2190 Prev" }), totalPages > 0 &&
283
- [...Array(Math.min(totalPages, 5))].map((_, i) => {
284
- const page = i + 1;
285
- return (_jsx("button", { className: `dl-page-btn ${currentPage === page ? "active" : ""}`, onClick: () => handlePageChange(page), children: page }, page));
286
- }), _jsx("button", { className: "dl-page-btn", disabled: !hasNext, onClick: handleNextPage, children: "Next \u2192" }), _jsx("button", { className: "dl-page-btn", disabled: !hasNext, onClick: handleLastPage, children: "Last" })] })] }));
292
+ return (_jsxs("div", { className: "dl-pagination", children: [_jsx("div", { className: "dl-pagination-info", children: showPageInfo && !showTotalCount && _jsxs("span", { children: ["Page ", currentPage] }) }), _jsxs("div", { className: "dl-pagination-controls", children: [showRowsPerPage && (_jsxs("div", { className: "dl-rows-per-page", children: [_jsx("span", { children: "Rows per page" }), _jsx("select", { value: rowsPerPage, onChange: (e) => handleRowsPerPage(Number(e.target.value)), children: rowsPerPageOptions.map((o) => (_jsx("option", { value: o, children: o }, o))) })] })), showPageInfo && showTotalCount && (_jsxs("span", { className: "text-sm", children: ["Page ", startRecord, " of ", endRecord] })), _jsxs("div", { className: "flex gap-2", children: [_jsx("button", { className: "dl-page-btn", disabled: !hasPrev, onClick: handleFirstPage, children: _jsx(ChevronLeft, { size: 16 }) }), _jsx("button", { className: "dl-page-btn", disabled: !hasPrev, onClick: handlePrevPage, children: _jsx(ChevronsLeft, { size: 16 }) }), totalPages > 0 &&
293
+ [...Array(Math.min(totalPages, 5))].map((_, i) => {
294
+ const page = i + 1;
295
+ return (_jsx("button", { className: `dl-page-btn ${currentPage === page ? "active" : ""}`, onClick: () => handlePageChange(page), children: page }, page));
296
+ }), _jsx("button", { className: "dl-page-btn", disabled: !hasNext, onClick: handleNextPage, children: _jsx(ChevronRight, { size: 16 }) }), _jsx("button", { className: "dl-page-btn", disabled: !hasNext, onClick: handleLastPage, children: _jsx(ChevronsRight, { size: 16 }) })] })] })] }));
287
297
  };
288
298
  // ============================================================================
289
299
  // ERROR STATE
@@ -294,7 +304,8 @@ const InnerDataList = ({ cols, emptyMessage = "No data available", errorMessage,
294
304
  // ============================================================================
295
305
  // MAIN RENDER
296
306
  // ============================================================================
297
- return (_jsxs("div", { className: `data-list ${className}`, children: [renderToolbar(), renderFilterPanel(), (paginationPosition === "both" || paginationPosition === "top") && renderPagination(), _jsx(DataTable, { data: rows, columns: sortableColumns, loading: isLoading, emptyMessage: emptyMessage, striped: striped, bordered: bordered, hover: hover, dense: dense, rowKey: "id", onRowClick: handleRowClick, selectedRows: selectedRows, onSelectionChange: handleSelectionChange, selectable: selectable, rowClassName: rowClassName }), (paginationPosition === "both" || paginationPosition === "bottom") && rows.length > 0 && renderPagination()] }));
307
+ const rowsPerPage = (_a = listHandler === null || listHandler === void 0 ? void 0 : listHandler.getRowsPerPage()) !== null && _a !== void 0 ? _a : 10;
308
+ return (_jsxs("div", { className: `data-list ${className}`, children: [renderToolbar(), renderFilterPanel(), (paginationPosition === "both" || paginationPosition === "top") && renderPagination(), _jsx(DataTable, { data: rows, columns: sortableColumns, loading: isLoading, emptyMessage: emptyMessage, striped: striped, bordered: bordered, hover: hover, dense: dense, rowKey: "id", onRowClick: handleRowClick, selectedRows: selectedRows, onSelectionChange: handleSelectionChange, selectable: selectable, rowClassName: rowClassName, rowsPerPage: rowsPerPage }), (paginationPosition === "both" || paginationPosition === "bottom") && rows.length > 0 && renderPagination()] }));
298
309
  };
299
310
  export const DataList = ({ attr }) => {
300
311
  const { title, depends, cols, data, rowsPerPage, disableTotalCount, commonActions, rowActions, toolbarActions } = attr, rest = __rest(attr, ["title", "depends", "cols", "data", "rowsPerPage", "disableTotalCount", "commonActions", "rowActions", "toolbarActions"]);
@@ -337,13 +348,17 @@ export const DataList = ({ attr }) => {
337
348
  attr: Object.assign(Object.assign({}, commonActions.newPage), { title: "New" }),
338
349
  });
339
350
  }
340
- if (commonActions === null || commonActions === void 0 ? void 0 : commonActions.filterPage) {
341
- newToolbarActions.push({
342
- label: "Filter",
343
- component: "LookupPage",
344
- attr: Object.assign(Object.assign({}, commonActions.filterPage), { name: "customFilter", title: "Filter" }),
345
- });
346
- }
351
+ // if (commonActions?.filterPage) {
352
+ // newToolbarActions.push({
353
+ // label: "Filter",
354
+ // component: "LookupPage",
355
+ // attr: {
356
+ // ...commonActions.filterPage,
357
+ // name: "customFilter",
358
+ // title: "Filter",
359
+ // },
360
+ // });
361
+ // }
347
362
  const handleRef = useRef(null);
348
363
  const onRefresh = () => {
349
364
  var _a;
@@ -356,17 +371,21 @@ export const DataList = ({ attr }) => {
356
371
  handleRef.current = ref;
357
372
  },
358
373
  };
359
- return (_jsx(TableProvider, { data: data, columns: cols, rowsPerPage: rowsPerPage, disableTotalCount: disableTotalCount, listHandlerFactory: listHandlerFactory, tenant: tenant !== null && tenant !== void 0 ? tenant : "", module: module !== null && module !== void 0 ? module : "", resolvedParams: resolveParams(), children: _jsx(InnerDataList, Object.assign({}, rest, { toolbarTitle: title, cols: cols, rowActions: newRowActions, toolbarActions: newToolbarActions, depends: depends, handle: innerHandle })) }));
374
+ return (_jsx(TableProvider, { data: data, columns: cols, rowsPerPage: rowsPerPage, disableTotalCount: disableTotalCount, listHandlerFactory: listHandlerFactory, tenant: tenant !== null && tenant !== void 0 ? tenant : "", module: module !== null && module !== void 0 ? module : "", resolvedParams: resolveParams(), children: _jsx(InnerDataList, Object.assign({}, rest, { toolbarTitle: title, cols: cols, rowActions: newRowActions, toolbarActions: newToolbarActions, depends: depends, handle: innerHandle, filterPage: commonActions === null || commonActions === void 0 ? void 0 : commonActions.filterPage })) }));
360
375
  };
361
376
  export default DataList;
362
377
  const RefreshButton = ({ show, onClick, size = 18 }) => {
363
378
  if (!show)
364
379
  return null;
365
- return (_jsx("span", { className: "text-gray-600 hover:bg-gray-200 rounded p-2", children: _jsx(RefreshCcw, { size: size, onClick: onClick, className: "cursor-pointer" }) }));
380
+ return (_jsx(Tooltip, { content: "Refresh", children: _jsx("span", { className: "text-gray-600 hover:bg-gray-200 rounded p-2 cursor-pointer flex items-center", onClick: onClick, children: _jsx(RefreshCcw, { size: size }) }) })
381
+ // <Button onClick={onClick} variant="outlined" icon={<RefreshCcw size={size} />} className="text-black border-gray-300 hover:bg-gray-100">
382
+ // Refresh
383
+ // </Button>
384
+ );
366
385
  };
367
386
  const ColumnToggle = ({ columns, hiddenColumns, setHiddenColumns }) => {
368
387
  const [showColumnToggle, setShowColumnToggle] = useState(false);
369
- return (_jsxs("div", { className: "relative", children: [_jsx("span", { className: "text-gray-600 hover:bg-gray-200 rounded p-2 cursor-pointer flex items-center", onClick: () => setShowColumnToggle(!showColumnToggle), children: _jsx(Columns, { size: 18 }) }), showColumnToggle && (_jsxs("div", { className: "absolute right-0 top-8 z-50 bg-white border border-gray-200 rounded-lg shadow-lg p-3 min-w-[180px]", children: [_jsx("p", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wide mb-2", children: "Columns" }), columns.map((col) => {
388
+ return (_jsxs("div", { className: "relative", children: [_jsx(Tooltip, { content: "Columns", children: _jsx("span", { className: "text-gray-600 hover:bg-gray-200 rounded p-2 cursor-pointer flex items-center", onClick: () => setShowColumnToggle(!showColumnToggle), children: _jsx(Columns, { size: 18 }) }) }), showColumnToggle && (_jsxs("div", { className: "absolute right-0 top-8 z-50 bg-white border rounded-lg shadow-lg p-3 min-w-[180px]", children: [_jsx("p", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wide mb-2", children: "Columns" }), columns.map((col) => {
370
389
  const colId = col.id || String(col.title);
371
390
  const isHidden = hiddenColumns.includes(colId);
372
391
  return (_jsxs("label", { className: "flex items-center gap-2 py-1 cursor-pointer hover:bg-gray-50 px-1 rounded", children: [_jsx("input", { type: "checkbox", checked: !isHidden, onChange: () => setHiddenColumns((prev) => (isHidden ? prev.filter((id) => id !== colId) : [...prev, colId])) }), _jsx("span", { className: "text-sm text-gray-700", children: String(col.title || col.id) })] }, colId));
@@ -375,5 +394,11 @@ const ColumnToggle = ({ columns, hiddenColumns, setHiddenColumns }) => {
375
394
  const SearchBox = ({ searchable, searchPlaceholder, searchText, onSearch }) => {
376
395
  if (!searchable)
377
396
  return null;
378
- return (_jsxs("div", { className: "dl-search-box ml-2", children: [_jsx("span", { children: _jsx(Search, { size: 16 }) }), _jsx("input", { type: "text", placeholder: searchPlaceholder, value: searchText, onChange: (e) => onSearch(e.target.value), className: "focus:outline-none focus:ring-0 focus:shadow-none focus:bg-white" })] }));
397
+ return (_jsxs("div", { className: "dl-search-box", children: [_jsx("span", { children: _jsx(Search, { size: 16 }) }), _jsx("input", { type: "text", placeholder: searchPlaceholder, value: searchText, onChange: (e) => onSearch(e.target.value), className: "focus:outline-none focus:ring-0 focus:shadow-none focus:bg-white" })] }));
398
+ };
399
+ const FilterButton = ({ filterPage }) => {
400
+ const { url, name, icon } = filterPage || {};
401
+ if (!filterPage)
402
+ return null;
403
+ return (_jsx(Tooltip, { content: "Filter", children: _jsx(LookupPage, { url: url, name: name, title: "Filter", icon: icon || _jsx(Funnel, { size: 18, className: "cursor-pointer text-black " }), iconOnly: true, variant: "outlined", className: "text-gray-600 hover:bg-gray-200 rounded p-2 flex items-center" }) }));
379
404
  };
@@ -16,6 +16,7 @@ export interface ColumnDefinition {
16
16
  expr?: string;
17
17
  primary?: boolean;
18
18
  component?: string | null;
19
+ attr?: Record<string, any>;
19
20
  }
20
21
  export interface DataTableProps {
21
22
  data?: any[];
@@ -41,6 +42,7 @@ export interface DataTableProps {
41
42
  multiRowHeader?: ColumnDefinition[][];
42
43
  rowActions?: (row: any, rowIndex: number) => React.ReactNode;
43
44
  rowsPerItem?: number;
45
+ rowsPerPage?: number;
44
46
  }
45
47
  export declare const DataTable: React.FC<DataTableProps>;
46
48
  export default DataTable;
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import React, { memo, useMemo } from "react";
3
+ import { DynamicComponent } from "../../core/DynamicComponent";
3
4
  import { RowProvider } from "../../core/RowContext";
4
5
  import { render } from "../../lib/utils/ExprUtil";
5
6
  import { useTableContext } from "./TableContext";
@@ -53,7 +54,7 @@ const TableHeader = memo(({ visibleColumns, selectable, rowActions, data, select
53
54
  return (_jsx("th", { style: { width: column.width, textAlign: column.align || "left" }, className: column.sortable ? "sortable" : "", children: renderHeader(column) }, getColumnKey(column, index)));
54
55
  }), rowActions && _jsx("th", { className: "dt-actions-cell", children: "Actions" })] }));
55
56
  });
56
- const TableBody = memo(({ sortedData, visibleColumns, emptyMessage, selectable, rowActions, selectedRows, handleSelectRow, handleRowClick, handleCellClick, rowClassName, rowKey, rowsPerItem, cellRenderer, }) => {
57
+ const TableBody = memo(({ sortedData, visibleColumns, emptyMessage, selectable, rowActions, selectedRows, handleSelectRow, handleRowClick, handleCellClick, rowClassName, rowKey, rowsPerItem, cellRenderer, rowsPerPage, }) => {
57
58
  const generateKey = () => `RP-${Math.random().toString(36).slice(2)}`;
58
59
  const getNestedValue = (obj, path) => {
59
60
  if (!path)
@@ -63,6 +64,8 @@ const TableBody = memo(({ sortedData, visibleColumns, emptyMessage, selectable,
63
64
  const getRowKey = (row) => row[rowKey] || JSON.stringify(row);
64
65
  const isRowSelected = (row) => selectedRows.includes(getRowKey(row));
65
66
  const getColumnKey = (column, index) => column.id || column.expr || `col-${index}`;
67
+ const colCount = visibleColumns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0);
68
+ const fillerCount = rowsPerPage ? Math.max(0, rowsPerPage - sortedData.length) : 0;
66
69
  /*
67
70
  const renderExpression = (expr: string, row: any): string => {
68
71
  try {
@@ -92,6 +95,12 @@ const TableBody = memo(({ sortedData, visibleColumns, emptyMessage, selectable,
92
95
  }
93
96
  };
94
97
  const renderCellContent = (row, column, rowIndex) => {
98
+ if (column.component) {
99
+ return (_jsx(DynamicComponent, { config: {
100
+ component: column.component,
101
+ attr: Object.assign(Object.assign({}, column.attr), { opt: { data: row } }),
102
+ } }));
103
+ }
95
104
  if (column.expr) {
96
105
  const rendered = render(column.expr, row);
97
106
  if (column.render)
@@ -110,35 +119,35 @@ const TableBody = memo(({ sortedData, visibleColumns, emptyMessage, selectable,
110
119
  if (!sortedData || sortedData.length === 0) {
111
120
  return (_jsx("tr", { children: _jsx("td", { colSpan: visibleColumns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0), style: { textAlign: "center", padding: "24px" }, children: emptyMessage }) }));
112
121
  }
113
- return (_jsx(_Fragment, { children: sortedData.map((row, itemIndex) => {
114
- const isSelected = isRowSelected(row);
115
- const customRowClass = rowClassName ? rowClassName(row, itemIndex) : "";
116
- const rows = [];
117
- for (let subrowIndex = 0; subrowIndex < rowsPerItem; subrowIndex++) {
118
- const rowClasses = [isSelected && "dt-selected", customRowClass].filter(Boolean).join(" ");
119
- rows.push(_jsx(RowProvider, { data: row, children: _jsxs("tr", { className: rowClasses, onClick: () => handleRowClick(row, itemIndex), children: [selectable && subrowIndex === 0 && (_jsx("td", { className: "dt-checkbox-cell", rowSpan: rowsPerItem, children: _jsx("input", { type: "checkbox", checked: isSelected, onChange: () => handleSelectRow(row), onClick: (e) => e.stopPropagation() }) })), visibleColumns.map((column, colIndex) => {
120
- if (!column.id && !column.expr)
121
- return null;
122
- if ((column.subrow || 0) !== subrowIndex)
123
- return null;
124
- if (column.subrow && column.subrow > 0 && subrowIndex > 0)
125
- return null;
126
- const value = column.id ? getNestedValue(row, column.id) : null;
127
- return (_jsx("td", { style: { textAlign: column.align || "left" }, className: `
122
+ return (_jsxs(_Fragment, { children: [sortedData.map((row, itemIndex) => {
123
+ const isSelected = isRowSelected(row);
124
+ const customRowClass = rowClassName ? rowClassName(row, itemIndex) : "";
125
+ const rows = [];
126
+ for (let subrowIndex = 0; subrowIndex < rowsPerItem; subrowIndex++) {
127
+ const rowClasses = [isSelected && "dt-selected", customRowClass].filter(Boolean).join(" ");
128
+ rows.push(_jsx(RowProvider, { data: row, children: _jsxs("tr", { className: rowClasses, onClick: () => handleRowClick(row, itemIndex), children: [selectable && subrowIndex === 0 && (_jsx("td", { className: "dt-checkbox-cell", rowSpan: rowsPerItem, children: _jsx("input", { type: "checkbox", checked: isSelected, onChange: () => handleSelectRow(row), onClick: (e) => e.stopPropagation() }) })), visibleColumns.map((column, colIndex) => {
129
+ if (!column.id && !column.expr && !column.component)
130
+ return null;
131
+ if ((column.subrow || 0) !== subrowIndex)
132
+ return null;
133
+ if (column.subrow && column.subrow > 0 && subrowIndex > 0)
134
+ return null;
135
+ const value = column.id ? getNestedValue(row, column.id) : null;
136
+ return (_jsx("td", { style: { textAlign: column.align || "left" }, className: `
128
137
  ${column.datatype === "number" || column.datatype === "currency" ? "dt-numeric" : ""}
129
138
  ${column.datatype === "boolean" ? "dt-boolean" : ""}
130
139
  `.trim(), onClick: (e) => handleCellClick(e, value, row, column, itemIndex, colIndex), children: renderCellContent(row, column, itemIndex) }, getColumnKey(column, colIndex)));
131
- }), rowActions && subrowIndex === 0 && (_jsx("td", { className: "dt-actions-cell", rowSpan: rowsPerItem, children: rowActions(row, itemIndex) }))] }, `${getRowKey(row)}-subrow-${subrowIndex}`) }, generateKey()));
132
- }
133
- return rows;
134
- }) }));
140
+ }), rowActions && subrowIndex === 0 && (_jsx("td", { className: "dt-actions-cell", rowSpan: rowsPerItem, children: rowActions(row, itemIndex) }))] }, `${getRowKey(row)}-subrow-${subrowIndex}`) }, generateKey()));
141
+ }
142
+ return rows;
143
+ }), [...Array(fillerCount)].map((_, i) => (_jsx("tr", { className: "filler-row", children: [...Array(colCount)].map((_, j) => (_jsx("td", { children: "\u00A0" }, j))) }, `filler-${i}`)))] }));
135
144
  });
136
145
  // ============================================================================
137
146
  // DATATABLE COMPONENT
138
147
  // ============================================================================
139
148
  export const DataTable = ({
140
149
  // Direct props (fallback when used outside TableProvider)
141
- data: propData, columns: propColumns, loading: propLoading = false, emptyMessage = "No data available", striped = false, bordered = false, hover = true, dense = false, stickyHeader = false, maxHeight, rowKey = "id", onRowClick, onCellClick, selectedRows = [], onSelectionChange, selectable = false, className = "", rowClassName, cellRenderer, headerRenderer, multiRowHeader, rowActions, rowsPerItem = 1, }) => {
150
+ data: propData, columns: propColumns, loading: propLoading = false, emptyMessage = "No data available", striped = false, bordered = false, hover = true, dense = false, stickyHeader = false, maxHeight, rowKey = "id", onRowClick, onCellClick, selectedRows = [], onSelectionChange, selectable = false, className = "", rowClassName, cellRenderer, headerRenderer, multiRowHeader, rowActions, rowsPerItem = 1, rowsPerPage = 10, }) => {
142
151
  var _a, _b;
143
152
  // Try to consume context; if not inside a provider, ctx will be null.
144
153
  let ctxColumns;
@@ -248,6 +257,6 @@ data: propData, columns: propColumns, loading: propLoading = false, emptyMessage
248
257
  if (loading) {
249
258
  return (_jsxs("div", { className: "dt-loading", children: [_jsx("div", { className: "dt-spinner" }), _jsx("p", { children: "Loading..." })] }));
250
259
  }
251
- return (_jsx("div", { className: "dt-container", style: containerStyle, children: _jsxs("table", { className: tableClasses, children: [_jsx("thead", { children: _jsx(TableHeader, { visibleColumns: visibleColumns, selectable: selectable, rowActions: rowActions, data: data, selectedRows: selectedRows, handleSelectAll: handleSelectAll, sortConfig: sortConfig, handleSort: handleSort, headerRenderer: headerRenderer, multiRowHeader: multiRowHeader }) }), _jsx("tbody", { children: _jsx(TableBody, { sortedData: sortedData, visibleColumns: visibleColumns, emptyMessage: emptyMessage, selectable: selectable, rowActions: rowActions, selectedRows: selectedRows, handleSelectRow: handleSelectRow, handleRowClick: handleRowClick, handleCellClick: handleCellClick, rowClassName: rowClassName, rowKey: rowKey, rowsPerItem: rowsPerItem, cellRenderer: cellRenderer }) })] }) }));
260
+ return (_jsx("div", { className: "dt-container", style: containerStyle, children: _jsxs("table", { className: tableClasses, children: [_jsx("thead", { children: _jsx(TableHeader, { visibleColumns: visibleColumns, selectable: selectable, rowActions: rowActions, data: data, selectedRows: selectedRows, handleSelectAll: handleSelectAll, sortConfig: sortConfig, handleSort: handleSort, headerRenderer: headerRenderer, multiRowHeader: multiRowHeader }) }), _jsx("tbody", { children: _jsx(TableBody, { sortedData: sortedData, visibleColumns: visibleColumns, emptyMessage: emptyMessage, selectable: selectable, rowActions: rowActions, selectedRows: selectedRows, handleSelectRow: handleSelectRow, handleRowClick: handleRowClick, handleCellClick: handleCellClick, rowClassName: rowClassName, rowKey: rowKey, rowsPerItem: rowsPerItem, cellRenderer: cellRenderer, rowsPerPage: rowsPerPage }) })] }) }));
252
261
  };
253
262
  export default DataTable;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
- import VPanel from "../../layouts/VPanel";
2
+ import { VPanel } from "../../layouts/VPanel";
3
3
  import { renderListDef } from "../../lib/utils/SectionProvider";
4
4
  const FilterView = (props) => {
5
5
  const { items = [] } = props !== null && props !== void 0 ? props : {};