@reactorui/datagrid 1.0.20 → 1.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +273 -556
- package/dist/components/DataGrid/DataGrid.d.ts +1 -1
- package/dist/components/DataGrid/DataGrid.d.ts.map +1 -1
- package/dist/components/DataGrid/DataGrid.js +80 -47
- package/dist/components/Filter/FilterControls.d.ts +6 -2
- package/dist/components/Filter/FilterControls.d.ts.map +1 -1
- package/dist/components/Filter/FilterControls.js +114 -62
- package/dist/components/Table/TableHeader.d.ts +2 -1
- package/dist/components/Table/TableHeader.d.ts.map +1 -1
- package/dist/components/Table/TableHeader.js +4 -2
- package/dist/hooks/useDataGrid.d.ts +16 -18
- package/dist/hooks/useDataGrid.d.ts.map +1 -1
- package/dist/hooks/useDataGrid.js +139 -299
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/types/index.d.ts +76 -38
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/utils/index.d.ts +14 -5
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +166 -156
- package/package.json +1 -1
package/dist/types/index.d.ts
CHANGED
|
@@ -15,9 +15,10 @@ export interface Column<T = BaseRowData> {
|
|
|
15
15
|
align?: 'left' | 'center' | 'right';
|
|
16
16
|
render?: (value: any, row: T, index: number) => ReactNode;
|
|
17
17
|
}
|
|
18
|
+
export type FilterOperator = 'eq' | 'neq' | 'contains' | 'startsWith' | 'endsWith' | 'gt' | 'gte' | 'lt' | 'lte';
|
|
18
19
|
export interface ActiveFilter {
|
|
19
20
|
column: string;
|
|
20
|
-
operator: string;
|
|
21
|
+
operator: FilterOperator | string;
|
|
21
22
|
value: any;
|
|
22
23
|
dataType: string;
|
|
23
24
|
label: string;
|
|
@@ -35,38 +36,27 @@ export interface PaginationInfo {
|
|
|
35
36
|
end: number;
|
|
36
37
|
hasNext: boolean;
|
|
37
38
|
hasPrevious: boolean;
|
|
38
|
-
continuationToken?: string;
|
|
39
39
|
}
|
|
40
|
-
export interface
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
Count: number;
|
|
52
|
-
}
|
|
53
|
-
export interface HttpConfig {
|
|
54
|
-
bearerToken?: string;
|
|
55
|
-
apiKey?: string;
|
|
56
|
-
customHeaders?: Record<string, string>;
|
|
57
|
-
method?: 'GET' | 'POST';
|
|
58
|
-
postDataFormat?: 'form' | 'json';
|
|
59
|
-
withCredentials?: boolean;
|
|
60
|
-
timeout?: number;
|
|
40
|
+
export interface LoadingState {
|
|
41
|
+
/** Data is being fetched (shows table skeleton, disables all controls) */
|
|
42
|
+
data?: boolean;
|
|
43
|
+
/** Filter is being applied */
|
|
44
|
+
filter?: boolean;
|
|
45
|
+
/** Search is being executed */
|
|
46
|
+
search?: boolean;
|
|
47
|
+
/** Refresh is in progress */
|
|
48
|
+
refresh?: boolean;
|
|
49
|
+
/** Delete operation is in progress */
|
|
50
|
+
delete?: boolean;
|
|
61
51
|
}
|
|
62
|
-
export type OnDataLoadCallback<T = BaseRowData> = (data: ServerResponse<T>) => void;
|
|
63
|
-
export type OnDataErrorCallback = (error: Error, context: string) => void;
|
|
64
|
-
export type OnLoadingStateChangeCallback = (loading: boolean, context: string) => void;
|
|
65
52
|
export type OnPageChangeCallback = (page: number, paginationInfo: PaginationInfo) => void;
|
|
66
|
-
export type OnPageSizeChangeCallback = (pageSize: number
|
|
53
|
+
export type OnPageSizeChangeCallback = (pageSize: number) => void;
|
|
67
54
|
export type OnSortChangeCallback = (sortConfig: SortConfig) => void;
|
|
68
|
-
export type OnFilterChangeCallback = (filters: ActiveFilter[]) => void;
|
|
69
55
|
export type OnSearchChangeCallback = (searchTerm: string) => void;
|
|
56
|
+
export type OnApplyFilterCallback = (filter: ActiveFilter, allFilters: ActiveFilter[]) => void;
|
|
57
|
+
export type OnRemoveFilterCallback = (removedFilter: ActiveFilter, remainingFilters: ActiveFilter[]) => void;
|
|
58
|
+
export type OnClearFiltersCallback = () => void;
|
|
59
|
+
export type OnFilterChangeCallback = (filters: ActiveFilter[]) => void;
|
|
70
60
|
export type OnTableRowClickCallback<T = BaseRowData> = (row: T, event: React.MouseEvent) => void;
|
|
71
61
|
export type OnTableRowDoubleClickCallback<T = BaseRowData> = (row: T, event: React.MouseEvent) => boolean | void;
|
|
72
62
|
export type OnRowSelectCallback<T = BaseRowData> = (row: T, isSelected: boolean) => void;
|
|
@@ -76,38 +66,86 @@ export type OnCellClickCallback<T = BaseRowData> = (value: any, row: T, column:
|
|
|
76
66
|
export type OnTableRefreshCallback = () => void;
|
|
77
67
|
export type OnBulkDeleteCallback<T = BaseRowData> = (selectedRows: T[]) => void;
|
|
78
68
|
export interface DataGridProps<T = BaseRowData> extends Omit<HTMLAttributes<HTMLDivElement>, 'onError'> {
|
|
79
|
-
data
|
|
80
|
-
|
|
69
|
+
/** The data array to display - parent is responsible for fetching/filtering */
|
|
70
|
+
data: T[];
|
|
71
|
+
/** Column definitions - auto-detected if not provided */
|
|
81
72
|
columns?: Column<T>[];
|
|
73
|
+
/**
|
|
74
|
+
* Granular loading states for different actions.
|
|
75
|
+
* @example { data: true } - Shows table skeleton
|
|
76
|
+
* @example { filter: true } - Shows spinner on Apply Filter button
|
|
77
|
+
* @example { refresh: true } - Shows spinner on Refresh button
|
|
78
|
+
*/
|
|
79
|
+
loadingState?: LoadingState;
|
|
80
|
+
/**
|
|
81
|
+
* Simple loading flag - sets loadingState.data = true.
|
|
82
|
+
* Use this OR loadingState, not both.
|
|
83
|
+
* @deprecated Prefer loadingState for granular control
|
|
84
|
+
*/
|
|
85
|
+
loading?: boolean;
|
|
86
|
+
/** Total records for pagination display (server-side) */
|
|
87
|
+
totalRecords?: number;
|
|
88
|
+
/** Whether more data is available (server-side) */
|
|
89
|
+
hasMore?: boolean;
|
|
90
|
+
/** Error message to display */
|
|
91
|
+
error?: string | null;
|
|
82
92
|
enableSearch?: boolean;
|
|
83
93
|
enableSorting?: boolean;
|
|
84
94
|
enableFilters?: boolean;
|
|
85
95
|
enableSelection?: boolean;
|
|
86
96
|
enableDelete?: boolean;
|
|
97
|
+
enableRefresh?: boolean;
|
|
87
98
|
deleteConfirmation?: boolean;
|
|
88
99
|
pageSize?: number;
|
|
89
|
-
serverPageSize?: number;
|
|
90
100
|
pageSizeOptions?: number[];
|
|
91
|
-
|
|
92
|
-
|
|
101
|
+
/** Current page (controlled mode for server-side) */
|
|
102
|
+
currentPage?: number;
|
|
103
|
+
/**
|
|
104
|
+
* Set a max height for the grid - enables scrollable table body.
|
|
105
|
+
* Can be any CSS value: '400px', '50vh', 'calc(100vh - 200px)'
|
|
106
|
+
*/
|
|
107
|
+
maxHeight?: string | number;
|
|
108
|
+
/**
|
|
109
|
+
* Keep table header visible while scrolling (sticky header).
|
|
110
|
+
* Automatically enabled when maxHeight is set.
|
|
111
|
+
*/
|
|
112
|
+
stickyHeader?: boolean;
|
|
93
113
|
className?: string;
|
|
94
114
|
variant?: 'default' | 'striped' | 'bordered';
|
|
95
115
|
size?: 'sm' | 'md' | 'lg';
|
|
96
|
-
onDataLoad?: OnDataLoadCallback<T>;
|
|
97
|
-
onDataError?: OnDataErrorCallback;
|
|
98
|
-
onLoadingStateChange?: OnLoadingStateChangeCallback;
|
|
99
116
|
onPageChange?: OnPageChangeCallback;
|
|
100
117
|
onPageSizeChange?: OnPageSizeChangeCallback;
|
|
101
118
|
onSortChange?: OnSortChangeCallback;
|
|
102
|
-
onFilterChange?: OnFilterChangeCallback;
|
|
103
119
|
onSearchChange?: OnSearchChangeCallback;
|
|
104
|
-
|
|
120
|
+
/** Called when Apply Filter button is clicked */
|
|
121
|
+
onApplyFilter?: OnApplyFilterCallback;
|
|
122
|
+
/** Called when a filter tag is removed */
|
|
123
|
+
onRemoveFilter?: OnRemoveFilterCallback;
|
|
124
|
+
/** Called when Clear All is clicked */
|
|
125
|
+
onClearFilters?: OnClearFiltersCallback;
|
|
126
|
+
/** Called whenever filters change (convenience callback) */
|
|
127
|
+
onFilterChange?: OnFilterChangeCallback;
|
|
105
128
|
onTableRowClick?: OnTableRowClickCallback<T>;
|
|
106
129
|
onTableRowDoubleClick?: OnTableRowDoubleClickCallback<T>;
|
|
107
130
|
onRowSelect?: OnRowSelectCallback<T>;
|
|
108
131
|
onSelectionChange?: OnSelectionChangeCallback<T>;
|
|
109
132
|
onTableRowHover?: OnTableRowHoverCallback<T>;
|
|
110
133
|
onCellClick?: OnCellClickCallback<T>;
|
|
134
|
+
onTableRefresh?: OnTableRefreshCallback;
|
|
111
135
|
onBulkDelete?: OnBulkDeleteCallback<T>;
|
|
112
136
|
}
|
|
137
|
+
/** Request object that parent can use to build API calls */
|
|
138
|
+
export interface DataGridRequest {
|
|
139
|
+
page: number;
|
|
140
|
+
pageSize: number;
|
|
141
|
+
search: string;
|
|
142
|
+
filters: ActiveFilter[];
|
|
143
|
+
sort: SortConfig;
|
|
144
|
+
}
|
|
145
|
+
/** Helper type for building API responses */
|
|
146
|
+
export interface DataGridResponse<T = BaseRowData> {
|
|
147
|
+
items: T[];
|
|
148
|
+
totalRecords: number;
|
|
149
|
+
hasMore?: boolean;
|
|
150
|
+
}
|
|
113
151
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
package/dist/types/index.js
CHANGED
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ActiveFilter, SortConfig, DataGridRequest } from '../types';
|
|
2
2
|
export declare const formatters: {
|
|
3
3
|
date: (value: string, includeTime?: boolean) => string;
|
|
4
|
-
currency: (value: number, currency?: string) => string;
|
|
5
|
-
number: (value: number, decimals?: number) => string;
|
|
4
|
+
currency: (value: number, currency?: string, locale?: string) => string;
|
|
5
|
+
number: (value: number, decimals?: number, locale?: string) => string;
|
|
6
6
|
truncate: (text: string, length: number) => string;
|
|
7
|
+
percentage: (value: number, decimals?: number) => string;
|
|
7
8
|
};
|
|
8
9
|
export declare const compareValues: (dataValue: any, filterValue: any, operator: string, dataType: string) => boolean;
|
|
9
|
-
export declare const createApiRequest: <T>(endpoint: string, request: ServerRequest, config?: HttpConfig) => Promise<ServerResponse<T>>;
|
|
10
|
-
export declare const mapServerResponse: <T>(data: any) => ServerResponse<T>;
|
|
11
10
|
export declare const sortData: <T>(data: T[], sortColumn: string, direction: "asc" | "desc") => T[];
|
|
11
|
+
export declare const inferDataType: (value: any) => "string" | "number" | "boolean" | "date" | "datetime";
|
|
12
|
+
export declare const inferColumns: <T extends Record<string, any>>(data: T[]) => Array<{
|
|
13
|
+
key: string;
|
|
14
|
+
label: string;
|
|
15
|
+
sortable: boolean;
|
|
16
|
+
filterable: boolean;
|
|
17
|
+
dataType: "string" | "number" | "boolean" | "date" | "datetime";
|
|
18
|
+
}>;
|
|
19
|
+
export declare const generateRowId: <T extends Record<string, any>>(row: T, index: number) => string;
|
|
20
|
+
export declare const buildRequest: (page: number, pageSize: number, search: string, filters: ActiveFilter[], sort: SortConfig) => DataGridRequest;
|
|
12
21
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAM1E,eAAO,MAAM,UAAU;kBACP,MAAM,4BAAwB,MAAM;sBAMhC,MAAM,yCAAuC,MAAM;oBAOrD,MAAM,yCAAmC,MAAM;qBAO9C,MAAM,UAAU,MAAM,KAAG,MAAM;wBAK5B,MAAM,wBAAiB,MAAM;CAGlD,CAAC;AAMF,eAAO,MAAM,aAAa,GACxB,WAAW,GAAG,EACd,aAAa,GAAG,EAChB,UAAU,MAAM,EAChB,UAAU,MAAM,KACf,OAgBF,CAAC;AA0EF,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,MAAM,CAAC,EAAE,EAAE,YAAY,MAAM,EAAE,WAAW,KAAK,GAAG,MAAM,KAAG,CAAC,EA6BvF,CAAC;AAMF,eAAO,MAAM,aAAa,GACxB,OAAO,GAAG,KACT,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,UAiB7C,CAAC;AAMF,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACxD,MAAM,CAAC,EAAE,KACR,KAAK,CAAC;IACP,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;CACjE,CAWA,CAAC;AAcF,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,EAAE,OAAO,MAAM,KAAG,MAYpF,CAAC;AAMF,eAAO,MAAM,YAAY,GACvB,MAAM,MAAM,EACZ,UAAU,MAAM,EAChB,QAAQ,MAAM,EACd,SAAS,YAAY,EAAE,EACvB,MAAM,UAAU,KACf,eAMD,CAAC"}
|
package/dist/utils/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
//
|
|
1
|
+
// File: src/utils/index.ts
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// Data Formatting Utilities
|
|
4
|
+
// ============================================================================
|
|
2
5
|
export const formatters = {
|
|
3
6
|
date: (value, includeTime = false) => {
|
|
4
7
|
if (!value)
|
|
@@ -6,14 +9,14 @@ export const formatters = {
|
|
|
6
9
|
const date = new Date(value);
|
|
7
10
|
return includeTime ? date.toLocaleString() : date.toLocaleDateString();
|
|
8
11
|
},
|
|
9
|
-
currency: (value, currency = 'USD') => {
|
|
10
|
-
return new Intl.NumberFormat(
|
|
12
|
+
currency: (value, currency = 'USD', locale = 'en-US') => {
|
|
13
|
+
return new Intl.NumberFormat(locale, {
|
|
11
14
|
style: 'currency',
|
|
12
15
|
currency,
|
|
13
16
|
}).format(value);
|
|
14
17
|
},
|
|
15
|
-
number: (value, decimals = 0) => {
|
|
16
|
-
return new Intl.NumberFormat(
|
|
18
|
+
number: (value, decimals = 0, locale = 'en-US') => {
|
|
19
|
+
return new Intl.NumberFormat(locale, {
|
|
17
20
|
minimumFractionDigits: decimals,
|
|
18
21
|
maximumFractionDigits: decimals,
|
|
19
22
|
}).format(value);
|
|
@@ -23,187 +26,194 @@ export const formatters = {
|
|
|
23
26
|
return text;
|
|
24
27
|
return text.substring(0, length) + '...';
|
|
25
28
|
},
|
|
29
|
+
percentage: (value, decimals = 0) => {
|
|
30
|
+
return `${(value * 100).toFixed(decimals)}%`;
|
|
31
|
+
},
|
|
26
32
|
};
|
|
27
|
-
//
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// Filter Comparison Functions
|
|
35
|
+
// ============================================================================
|
|
28
36
|
export const compareValues = (dataValue, filterValue, operator, dataType) => {
|
|
29
37
|
if (dataValue == null)
|
|
30
38
|
return false;
|
|
31
39
|
switch (dataType) {
|
|
32
40
|
case 'string':
|
|
33
|
-
|
|
34
|
-
const filter = filterValue.toString().toLowerCase();
|
|
35
|
-
switch (operator) {
|
|
36
|
-
case 'eq':
|
|
37
|
-
return str === filter;
|
|
38
|
-
case 'contains':
|
|
39
|
-
return str.includes(filter);
|
|
40
|
-
case 'startsWith':
|
|
41
|
-
return str.startsWith(filter);
|
|
42
|
-
case 'endsWith':
|
|
43
|
-
return str.endsWith(filter);
|
|
44
|
-
default:
|
|
45
|
-
return str.includes(filter);
|
|
46
|
-
}
|
|
41
|
+
return compareString(dataValue, filterValue, operator);
|
|
47
42
|
case 'number':
|
|
48
|
-
|
|
49
|
-
const filterNum = parseFloat(filterValue);
|
|
50
|
-
switch (operator) {
|
|
51
|
-
case 'eq':
|
|
52
|
-
return num === filterNum;
|
|
53
|
-
case 'gt':
|
|
54
|
-
return num > filterNum;
|
|
55
|
-
case 'gte':
|
|
56
|
-
return num >= filterNum;
|
|
57
|
-
case 'lt':
|
|
58
|
-
return num < filterNum;
|
|
59
|
-
case 'lte':
|
|
60
|
-
return num <= filterNum;
|
|
61
|
-
default:
|
|
62
|
-
return num === filterNum;
|
|
63
|
-
}
|
|
43
|
+
return compareNumber(dataValue, filterValue, operator);
|
|
64
44
|
case 'date':
|
|
65
45
|
case 'datetime':
|
|
66
|
-
|
|
67
|
-
const filterDate = new Date(filterValue).getTime();
|
|
68
|
-
switch (operator) {
|
|
69
|
-
case 'eq':
|
|
70
|
-
return date === filterDate;
|
|
71
|
-
case 'gt':
|
|
72
|
-
return date > filterDate;
|
|
73
|
-
case 'gte':
|
|
74
|
-
return date >= filterDate;
|
|
75
|
-
case 'lt':
|
|
76
|
-
return date < filterDate;
|
|
77
|
-
case 'lte':
|
|
78
|
-
return date <= filterDate;
|
|
79
|
-
default:
|
|
80
|
-
return date === filterDate;
|
|
81
|
-
}
|
|
46
|
+
return compareDate(dataValue, filterValue, operator);
|
|
82
47
|
case 'boolean':
|
|
83
|
-
return Boolean(dataValue) ===
|
|
48
|
+
return Boolean(dataValue) === (filterValue === 'true' || filterValue === true);
|
|
84
49
|
default:
|
|
85
50
|
return String(dataValue).toLowerCase().includes(String(filterValue).toLowerCase());
|
|
86
51
|
}
|
|
87
52
|
};
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
method,
|
|
105
|
-
headers,
|
|
106
|
-
credentials: withCredentials ? 'include' : 'same-origin',
|
|
107
|
-
};
|
|
108
|
-
let url = endpoint;
|
|
109
|
-
if (method === 'POST') {
|
|
110
|
-
requestOptions.body = JSON.stringify({ request });
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
const params = new URLSearchParams({ request: JSON.stringify(request) });
|
|
114
|
-
url = `${endpoint}?${params.toString()}`;
|
|
115
|
-
}
|
|
116
|
-
// Create timeout
|
|
117
|
-
const controller = new AbortController();
|
|
118
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
119
|
-
requestOptions.signal = controller.signal;
|
|
120
|
-
try {
|
|
121
|
-
const response = await fetch(url, requestOptions);
|
|
122
|
-
clearTimeout(timeoutId);
|
|
123
|
-
if (!response.ok) {
|
|
124
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
125
|
-
}
|
|
126
|
-
const data = await response.json();
|
|
127
|
-
return mapServerResponse(data);
|
|
128
|
-
}
|
|
129
|
-
catch (error) {
|
|
130
|
-
clearTimeout(timeoutId);
|
|
131
|
-
throw error;
|
|
53
|
+
const compareString = (value, filter, operator) => {
|
|
54
|
+
const str = String(value).toLowerCase();
|
|
55
|
+
const filterStr = String(filter).toLowerCase();
|
|
56
|
+
switch (operator) {
|
|
57
|
+
case 'eq':
|
|
58
|
+
return str === filterStr;
|
|
59
|
+
case 'neq':
|
|
60
|
+
return str !== filterStr;
|
|
61
|
+
case 'contains':
|
|
62
|
+
return str.includes(filterStr);
|
|
63
|
+
case 'startsWith':
|
|
64
|
+
return str.startsWith(filterStr);
|
|
65
|
+
case 'endsWith':
|
|
66
|
+
return str.endsWith(filterStr);
|
|
67
|
+
default:
|
|
68
|
+
return str.includes(filterStr);
|
|
132
69
|
}
|
|
133
70
|
};
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
'
|
|
149
|
-
|
|
150
|
-
'
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
]);
|
|
155
|
-
// Get hasMore with flexible casing
|
|
156
|
-
const hasMore = getValue(data, [
|
|
157
|
-
'HasMore',
|
|
158
|
-
'hasMore',
|
|
159
|
-
'hasmore',
|
|
160
|
-
'has_more',
|
|
161
|
-
'hasNextPage',
|
|
162
|
-
'has_next_page',
|
|
163
|
-
]);
|
|
164
|
-
// Get count with flexible casing
|
|
165
|
-
const count = getValue(data, ['Count', 'count', 'COUNT', 'total', 'Total', 'length', 'size']);
|
|
166
|
-
// Direct mapping for arrays
|
|
167
|
-
if (Array.isArray(data)) {
|
|
168
|
-
return {
|
|
169
|
-
Items: data,
|
|
170
|
-
HasMore: false,
|
|
171
|
-
Count: data.length,
|
|
172
|
-
};
|
|
71
|
+
const compareNumber = (value, filter, operator) => {
|
|
72
|
+
const num = parseFloat(value);
|
|
73
|
+
const filterNum = parseFloat(filter);
|
|
74
|
+
if (isNaN(num) || isNaN(filterNum))
|
|
75
|
+
return false;
|
|
76
|
+
switch (operator) {
|
|
77
|
+
case 'eq':
|
|
78
|
+
return num === filterNum;
|
|
79
|
+
case 'neq':
|
|
80
|
+
return num !== filterNum;
|
|
81
|
+
case 'gt':
|
|
82
|
+
return num > filterNum;
|
|
83
|
+
case 'gte':
|
|
84
|
+
return num >= filterNum;
|
|
85
|
+
case 'lt':
|
|
86
|
+
return num < filterNum;
|
|
87
|
+
case 'lte':
|
|
88
|
+
return num <= filterNum;
|
|
89
|
+
default:
|
|
90
|
+
return num === filterNum;
|
|
173
91
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
92
|
+
};
|
|
93
|
+
const compareDate = (value, filter, operator) => {
|
|
94
|
+
const date = new Date(value).getTime();
|
|
95
|
+
const filterDate = new Date(filter).getTime();
|
|
96
|
+
if (isNaN(date) || isNaN(filterDate))
|
|
97
|
+
return false;
|
|
98
|
+
switch (operator) {
|
|
99
|
+
case 'eq':
|
|
100
|
+
return date === filterDate;
|
|
101
|
+
case 'neq':
|
|
102
|
+
return date !== filterDate;
|
|
103
|
+
case 'gt':
|
|
104
|
+
return date > filterDate;
|
|
105
|
+
case 'gte':
|
|
106
|
+
return date >= filterDate;
|
|
107
|
+
case 'lt':
|
|
108
|
+
return date < filterDate;
|
|
109
|
+
case 'lte':
|
|
110
|
+
return date <= filterDate;
|
|
111
|
+
default:
|
|
112
|
+
return date === filterDate;
|
|
182
113
|
}
|
|
183
|
-
// Standard response mapping
|
|
184
|
-
return {
|
|
185
|
-
Items: Array.isArray(items) ? items : [],
|
|
186
|
-
ContinuationToken: continuationToken,
|
|
187
|
-
HasMore: Boolean(hasMore),
|
|
188
|
-
Count: Number(count) || 0,
|
|
189
|
-
};
|
|
190
114
|
};
|
|
191
|
-
//
|
|
115
|
+
// ============================================================================
|
|
116
|
+
// Sorting Utilities
|
|
117
|
+
// ============================================================================
|
|
192
118
|
export const sortData = (data, sortColumn, direction) => {
|
|
193
|
-
if (!sortColumn)
|
|
119
|
+
if (!sortColumn || data.length === 0)
|
|
194
120
|
return data;
|
|
195
121
|
return [...data].sort((a, b) => {
|
|
196
122
|
const aVal = a[sortColumn];
|
|
197
123
|
const bVal = b[sortColumn];
|
|
124
|
+
// Handle nulls - always sort to end
|
|
198
125
|
if (aVal == null && bVal == null)
|
|
199
126
|
return 0;
|
|
200
127
|
if (aVal == null)
|
|
201
128
|
return 1;
|
|
202
129
|
if (bVal == null)
|
|
203
130
|
return -1;
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
131
|
+
// Compare based on type
|
|
132
|
+
let result;
|
|
133
|
+
if (typeof aVal === 'number' && typeof bVal === 'number') {
|
|
134
|
+
result = aVal - bVal;
|
|
135
|
+
}
|
|
136
|
+
else if (aVal instanceof Date && bVal instanceof Date) {
|
|
137
|
+
result = aVal.getTime() - bVal.getTime();
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
// String comparison with natural sorting
|
|
141
|
+
result = String(aVal).localeCompare(String(bVal), undefined, {
|
|
142
|
+
numeric: true,
|
|
143
|
+
sensitivity: 'base',
|
|
144
|
+
});
|
|
145
|
+
}
|
|
207
146
|
return direction === 'desc' ? -result : result;
|
|
208
147
|
});
|
|
209
148
|
};
|
|
149
|
+
// ============================================================================
|
|
150
|
+
// Data Type Inference
|
|
151
|
+
// ============================================================================
|
|
152
|
+
export const inferDataType = (value) => {
|
|
153
|
+
if (value == null)
|
|
154
|
+
return 'string';
|
|
155
|
+
if (typeof value === 'boolean')
|
|
156
|
+
return 'boolean';
|
|
157
|
+
if (typeof value === 'number')
|
|
158
|
+
return 'number';
|
|
159
|
+
if (typeof value === 'string') {
|
|
160
|
+
// Check for ISO date format
|
|
161
|
+
const isoDateRegex = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2})?/;
|
|
162
|
+
if (isoDateRegex.test(value)) {
|
|
163
|
+
const date = new Date(value);
|
|
164
|
+
if (!isNaN(date.getTime()) && date.getFullYear() > 1900) {
|
|
165
|
+
return value.includes('T') ? 'datetime' : 'date';
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return 'string';
|
|
170
|
+
};
|
|
171
|
+
// ============================================================================
|
|
172
|
+
// Column Auto-Detection
|
|
173
|
+
// ============================================================================
|
|
174
|
+
export const inferColumns = (data) => {
|
|
175
|
+
if (data.length === 0)
|
|
176
|
+
return [];
|
|
177
|
+
const firstRow = data[0];
|
|
178
|
+
return Object.keys(firstRow).map((key) => ({
|
|
179
|
+
key,
|
|
180
|
+
label: formatColumnLabel(key),
|
|
181
|
+
sortable: true,
|
|
182
|
+
filterable: true,
|
|
183
|
+
dataType: inferDataType(firstRow[key]),
|
|
184
|
+
}));
|
|
185
|
+
};
|
|
186
|
+
const formatColumnLabel = (key) => {
|
|
187
|
+
return key
|
|
188
|
+
.replace(/([A-Z])/g, ' $1') // Add space before capitals
|
|
189
|
+
.replace(/[_-]/g, ' ') // Replace underscores/hyphens with spaces
|
|
190
|
+
.replace(/^\w/, (c) => c.toUpperCase()) // Capitalize first letter
|
|
191
|
+
.trim();
|
|
192
|
+
};
|
|
193
|
+
// ============================================================================
|
|
194
|
+
// Row ID Utilities
|
|
195
|
+
// ============================================================================
|
|
196
|
+
export const generateRowId = (row, index) => {
|
|
197
|
+
// Prefer existing id field
|
|
198
|
+
if (row.id !== undefined)
|
|
199
|
+
return String(row.id);
|
|
200
|
+
if (row._id !== undefined)
|
|
201
|
+
return String(row._id);
|
|
202
|
+
if (row.key !== undefined)
|
|
203
|
+
return String(row.key);
|
|
204
|
+
// Generate stable ID from content
|
|
205
|
+
const contentHash = JSON.stringify(row)
|
|
206
|
+
.slice(0, 50)
|
|
207
|
+
.replace(/[^a-zA-Z0-9]/g, '');
|
|
208
|
+
return `row-${index}-${contentHash}`;
|
|
209
|
+
};
|
|
210
|
+
// ============================================================================
|
|
211
|
+
// Export Helper for Building Requests (for parent component use)
|
|
212
|
+
// ============================================================================
|
|
213
|
+
export const buildRequest = (page, pageSize, search, filters, sort) => ({
|
|
214
|
+
page,
|
|
215
|
+
pageSize,
|
|
216
|
+
search,
|
|
217
|
+
filters,
|
|
218
|
+
sort,
|
|
219
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reactorui/datagrid",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.21",
|
|
4
4
|
"description": "High-performance React data grid with TypeScript support, server-side integration, and continuation token pagination",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|