react-restyle-components 0.4.25 → 0.4.27
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/lib/src/core-components/src/components/Table/Table.d.ts.map +1 -1
- package/lib/src/core-components/src/components/Table/Table.js +153 -27
- package/lib/src/core-components/src/components/Table/elements.d.ts +3 -0
- package/lib/src/core-components/src/components/Table/elements.d.ts.map +1 -1
- package/lib/src/core-components/src/components/Table/elements.js +102 -76
- package/lib/src/core-components/src/components/Table/filters.d.ts +225 -8
- package/lib/src/core-components/src/components/Table/filters.d.ts.map +1 -1
- package/lib/src/core-components/src/components/Table/filters.js +403 -65
- package/lib/src/core-components/src/components/Table/index.d.ts +1 -0
- package/lib/src/core-components/src/components/Table/index.d.ts.map +1 -1
- package/lib/src/core-components/src/components/Table/types.d.ts +21 -3
- package/lib/src/core-components/src/components/Table/types.d.ts.map +1 -1
- package/lib/src/core-components/src/tc.global.css +23 -2
- package/lib/src/core-components/src/tc.module.css +3 -2
- package/package.json +1 -1
|
@@ -1,58 +1,81 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { useState, useCallback } from 'react';
|
|
3
|
+
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
4
4
|
import { styled, css } from 'styled-components';
|
|
5
5
|
import { tokens } from '../../utils/designTokens';
|
|
6
6
|
// Styled components for filters
|
|
7
7
|
const FilterContainer = styled.div `
|
|
8
8
|
display: flex;
|
|
9
9
|
align-items: center;
|
|
10
|
-
gap:
|
|
10
|
+
gap: 3px;
|
|
11
11
|
`;
|
|
12
12
|
const FilterInputBase = styled.input `
|
|
13
13
|
width: 100%;
|
|
14
|
-
height:
|
|
15
|
-
padding: 0
|
|
16
|
-
font-size:
|
|
17
|
-
|
|
18
|
-
border
|
|
14
|
+
height: 22px;
|
|
15
|
+
padding: 0 5px;
|
|
16
|
+
font-size: 10px;
|
|
17
|
+
color: #000000;
|
|
18
|
+
border: 1px solid ${tokens.outline || '#e2e8f0'};
|
|
19
|
+
border-radius: 2px;
|
|
19
20
|
background: white;
|
|
20
|
-
|
|
21
|
+
transition: all 0.15s ease;
|
|
22
|
+
|
|
23
|
+
&:hover {
|
|
24
|
+
border-color: ${tokens.primary || '#94a3b8'};
|
|
25
|
+
}
|
|
26
|
+
|
|
21
27
|
&:focus {
|
|
22
28
|
outline: none;
|
|
23
29
|
border-color: ${tokens.primary || '#3b82f6'};
|
|
30
|
+
box-shadow: 0 0 0 1px
|
|
31
|
+
${tokens.primary ? `${tokens.primary}20` : '#3b82f620'};
|
|
24
32
|
}
|
|
25
|
-
|
|
33
|
+
|
|
26
34
|
&::placeholder {
|
|
27
|
-
color: ${tokens.onSurface ? `${tokens.onSurface}
|
|
35
|
+
color: ${tokens.onSurface ? `${tokens.onSurface}50` : '#94a3af'};
|
|
36
|
+
font-size: 9px;
|
|
28
37
|
}
|
|
29
38
|
`;
|
|
30
39
|
const FilterSelectBase = styled.select `
|
|
31
40
|
width: 100%;
|
|
32
|
-
height:
|
|
33
|
-
padding: 0
|
|
34
|
-
font-size:
|
|
35
|
-
|
|
36
|
-
border
|
|
41
|
+
height: 22px;
|
|
42
|
+
padding: 0 5px;
|
|
43
|
+
font-size: 10px;
|
|
44
|
+
color: #000000;
|
|
45
|
+
border: 1px solid ${tokens.outline || '#e2e8f0'};
|
|
46
|
+
border-radius: 2px;
|
|
37
47
|
background: white;
|
|
38
48
|
cursor: pointer;
|
|
39
|
-
|
|
49
|
+
transition: all 0.15s ease;
|
|
50
|
+
|
|
51
|
+
&:hover {
|
|
52
|
+
border-color: ${tokens.primary || '#94a3b8'};
|
|
53
|
+
}
|
|
54
|
+
|
|
40
55
|
&:focus {
|
|
41
56
|
outline: none;
|
|
42
57
|
border-color: ${tokens.primary || '#3b82f6'};
|
|
58
|
+
box-shadow: 0 0 0 1px
|
|
59
|
+
${tokens.primary ? `${tokens.primary}20` : '#3b82f620'};
|
|
43
60
|
}
|
|
44
61
|
`;
|
|
45
62
|
const ComparatorSelect = styled.select `
|
|
46
|
-
width:
|
|
47
|
-
height:
|
|
48
|
-
padding: 0
|
|
49
|
-
font-size:
|
|
50
|
-
border: 1px solid ${tokens.outline || '#
|
|
51
|
-
border-radius:
|
|
63
|
+
width: 38px;
|
|
64
|
+
height: 22px;
|
|
65
|
+
padding: 0 2px;
|
|
66
|
+
font-size: 9px;
|
|
67
|
+
border: 1px solid ${tokens.outline || '#e2e8f0'};
|
|
68
|
+
border-radius: 2px;
|
|
52
69
|
background: white;
|
|
53
70
|
cursor: pointer;
|
|
54
71
|
flex-shrink: 0;
|
|
55
|
-
|
|
72
|
+
text-align: center;
|
|
73
|
+
transition: all 0.15s ease;
|
|
74
|
+
|
|
75
|
+
&:hover {
|
|
76
|
+
border-color: ${tokens.primary || '#94a3b8'};
|
|
77
|
+
}
|
|
78
|
+
|
|
56
79
|
&:focus {
|
|
57
80
|
outline: none;
|
|
58
81
|
border-color: ${tokens.primary || '#3b82f6'};
|
|
@@ -60,30 +83,37 @@ const ComparatorSelect = styled.select `
|
|
|
60
83
|
`;
|
|
61
84
|
const DateInput = styled.input `
|
|
62
85
|
flex: 1;
|
|
63
|
-
height:
|
|
64
|
-
padding: 0
|
|
65
|
-
font-size:
|
|
66
|
-
border: 1px solid ${tokens.outline || '#
|
|
67
|
-
border-radius:
|
|
86
|
+
height: 22px;
|
|
87
|
+
padding: 0 4px;
|
|
88
|
+
font-size: 10px;
|
|
89
|
+
border: 1px solid ${tokens.outline || '#e2e8f0'};
|
|
90
|
+
border-radius: 2px;
|
|
68
91
|
background: white;
|
|
69
|
-
min-width:
|
|
70
|
-
|
|
92
|
+
min-width: 80px;
|
|
93
|
+
transition: all 0.15s ease;
|
|
94
|
+
|
|
95
|
+
&:hover {
|
|
96
|
+
border-color: ${tokens.primary || '#94a3b8'};
|
|
97
|
+
}
|
|
98
|
+
|
|
71
99
|
&:focus {
|
|
72
100
|
outline: none;
|
|
73
101
|
border-color: ${tokens.primary || '#3b82f6'};
|
|
102
|
+
box-shadow: 0 0 0 1px
|
|
103
|
+
${tokens.primary ? `${tokens.primary}20` : '#3b82f620'};
|
|
74
104
|
}
|
|
75
105
|
`;
|
|
76
106
|
const ToggleButton = styled.button `
|
|
77
|
-
height:
|
|
78
|
-
padding: 0
|
|
79
|
-
font-size:
|
|
80
|
-
font-weight:
|
|
81
|
-
border: 1px solid ${tokens.outline || '#
|
|
82
|
-
border-radius:
|
|
107
|
+
height: 22px;
|
|
108
|
+
padding: 0 5px;
|
|
109
|
+
font-size: 9px;
|
|
110
|
+
font-weight: normal;
|
|
111
|
+
border: 1px solid ${tokens.outline || '#e2e8f0'};
|
|
112
|
+
border-radius: 2px;
|
|
83
113
|
cursor: pointer;
|
|
84
114
|
transition: all 0.15s ease;
|
|
85
115
|
white-space: nowrap;
|
|
86
|
-
|
|
116
|
+
|
|
87
117
|
${({ $active }) => $active
|
|
88
118
|
? css `
|
|
89
119
|
background: ${tokens.primary || '#3b82f6'};
|
|
@@ -93,45 +123,282 @@ const ToggleButton = styled.button `
|
|
|
93
123
|
: css `
|
|
94
124
|
background: white;
|
|
95
125
|
color: ${tokens.onSurface || '#374151'};
|
|
126
|
+
|
|
127
|
+
&:hover {
|
|
128
|
+
background: #f8fafc;
|
|
129
|
+
border-color: ${tokens.primary || '#94a3b8'};
|
|
130
|
+
}
|
|
96
131
|
`}
|
|
97
132
|
`;
|
|
98
133
|
/**
|
|
99
|
-
* Text filter component
|
|
134
|
+
* Internal Text filter component with options support
|
|
100
135
|
*/
|
|
101
|
-
|
|
102
|
-
|
|
136
|
+
const TextFilterComponent = ({ column, value, onChange, options }) => {
|
|
137
|
+
const { placeholder, className, style, defaultValue, delay = 0, getFilter, onFilter, id, disabled, } = options || {};
|
|
138
|
+
const [internalValue, setInternalValue] = useState(value || defaultValue || '');
|
|
139
|
+
const timeoutRef = useRef(null);
|
|
140
|
+
const isFirstRender = useRef(true);
|
|
141
|
+
const internalValueRef = useRef(internalValue);
|
|
142
|
+
// Keep ref in sync with state
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
internalValueRef.current = internalValue;
|
|
145
|
+
}, [internalValue]);
|
|
146
|
+
// Sync with external value changes
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
if (!isFirstRender.current) {
|
|
149
|
+
setInternalValue(value || '');
|
|
150
|
+
}
|
|
151
|
+
isFirstRender.current = false;
|
|
152
|
+
}, [value]);
|
|
153
|
+
// Provide filter instance via getFilter callback - only on mount
|
|
154
|
+
useEffect(() => {
|
|
155
|
+
if (getFilter) {
|
|
156
|
+
getFilter({
|
|
157
|
+
get value() {
|
|
158
|
+
return internalValueRef.current;
|
|
159
|
+
},
|
|
160
|
+
setValue: (newValue) => {
|
|
161
|
+
setInternalValue(newValue);
|
|
162
|
+
onChange(newValue || null);
|
|
163
|
+
onFilter?.(newValue);
|
|
164
|
+
},
|
|
165
|
+
clear: () => {
|
|
166
|
+
setInternalValue('');
|
|
167
|
+
onChange(null);
|
|
168
|
+
onFilter?.('');
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
173
|
+
}, [getFilter]);
|
|
174
|
+
const handleChange = useCallback((e) => {
|
|
175
|
+
const newValue = e.target.value;
|
|
176
|
+
setInternalValue(newValue);
|
|
177
|
+
if (timeoutRef.current) {
|
|
178
|
+
clearTimeout(timeoutRef.current);
|
|
179
|
+
}
|
|
180
|
+
if (delay > 0) {
|
|
181
|
+
timeoutRef.current = setTimeout(() => {
|
|
182
|
+
onChange(newValue || null);
|
|
183
|
+
onFilter?.(newValue);
|
|
184
|
+
}, delay);
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
onChange(newValue || null);
|
|
188
|
+
onFilter?.(newValue);
|
|
189
|
+
}
|
|
190
|
+
}, [onChange, onFilter, delay]);
|
|
191
|
+
// Cleanup timeout on unmount
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
return () => {
|
|
194
|
+
if (timeoutRef.current) {
|
|
195
|
+
clearTimeout(timeoutRef.current);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
}, []);
|
|
199
|
+
// If custom className is provided, use plain input to allow full CSS control
|
|
200
|
+
if (className) {
|
|
201
|
+
return (_jsx("input", { type: "text", id: id, value: internalValue, onChange: handleChange, placeholder: placeholder || column.filterPlaceholder || `Filter ${column.text}...`, className: className, style: {
|
|
202
|
+
width: '100%',
|
|
203
|
+
...style,
|
|
204
|
+
}, disabled: disabled }));
|
|
205
|
+
}
|
|
206
|
+
return (_jsx(FilterInputBase, { type: "text", id: id, value: internalValue, onChange: handleChange, placeholder: placeholder || column.filterPlaceholder || `Filter ${column.text}...`, style: style, disabled: disabled }));
|
|
103
207
|
};
|
|
208
|
+
export function TextFilter(optionsOrProps) {
|
|
209
|
+
// Check if it's being used as a factory function (options object without column/value/onChange)
|
|
210
|
+
if (!('column' in optionsOrProps) &&
|
|
211
|
+
!('value' in optionsOrProps) &&
|
|
212
|
+
!('onChange' in optionsOrProps)) {
|
|
213
|
+
// Factory function usage - return a component
|
|
214
|
+
const options = optionsOrProps;
|
|
215
|
+
const FilterWithOptions = (props) => (_jsx(TextFilterComponent, { ...props, options: options }));
|
|
216
|
+
FilterWithOptions.displayName = 'TextFilter';
|
|
217
|
+
return FilterWithOptions;
|
|
218
|
+
}
|
|
219
|
+
// Direct component usage
|
|
220
|
+
const props = optionsOrProps;
|
|
221
|
+
return _jsx(TextFilterComponent, { ...props });
|
|
222
|
+
}
|
|
104
223
|
/**
|
|
105
|
-
* Number filter component with
|
|
224
|
+
* Internal Number filter component with options support
|
|
106
225
|
*/
|
|
107
|
-
|
|
108
|
-
const [
|
|
109
|
-
const [
|
|
226
|
+
const NumberFilterComponent = ({ column, value, onChange, options }) => {
|
|
227
|
+
const { placeholder, className, style, defaultValue, delay = 0, defaultComparator = '=', allowDecimal = true, getFilter, onFilter, id, disabled, hideComparator, comparators = ['=', '!=', '>', '>=', '<', '<='], } = options || {};
|
|
228
|
+
const [number, setNumber] = useState(value?.number || defaultValue?.number || '');
|
|
229
|
+
const [comparator, setComparator] = useState(value?.comparator || defaultValue?.comparator || defaultComparator);
|
|
230
|
+
const timeoutRef = useRef(null);
|
|
231
|
+
const numberRef = useRef(number);
|
|
232
|
+
const comparatorRef = useRef(comparator);
|
|
233
|
+
// Keep refs in sync with state
|
|
234
|
+
useEffect(() => {
|
|
235
|
+
numberRef.current = number;
|
|
236
|
+
comparatorRef.current = comparator;
|
|
237
|
+
}, [number, comparator]);
|
|
238
|
+
// Sync with external value changes
|
|
239
|
+
useEffect(() => {
|
|
240
|
+
if (value) {
|
|
241
|
+
setNumber(value.number || '');
|
|
242
|
+
setComparator(value.comparator || defaultComparator);
|
|
243
|
+
}
|
|
244
|
+
}, [value, defaultComparator]);
|
|
245
|
+
// Provide filter instance via getFilter callback - only on mount
|
|
246
|
+
useEffect(() => {
|
|
247
|
+
if (getFilter) {
|
|
248
|
+
getFilter({
|
|
249
|
+
get value() {
|
|
250
|
+
return numberRef.current
|
|
251
|
+
? { number: numberRef.current, comparator: comparatorRef.current }
|
|
252
|
+
: null;
|
|
253
|
+
},
|
|
254
|
+
setValue: (newValue) => {
|
|
255
|
+
if (newValue) {
|
|
256
|
+
setNumber(newValue.number);
|
|
257
|
+
setComparator(newValue.comparator);
|
|
258
|
+
onChange(newValue);
|
|
259
|
+
onFilter?.(newValue);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
setNumber('');
|
|
263
|
+
onChange(null);
|
|
264
|
+
onFilter?.(null);
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
clear: () => {
|
|
268
|
+
setNumber('');
|
|
269
|
+
setComparator(defaultComparator);
|
|
270
|
+
onChange(null);
|
|
271
|
+
onFilter?.(null);
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
276
|
+
}, [getFilter]);
|
|
110
277
|
const handleChange = useCallback((newNumber, newComparator) => {
|
|
111
278
|
setNumber(newNumber);
|
|
112
279
|
setComparator(newComparator);
|
|
113
|
-
if (
|
|
114
|
-
|
|
280
|
+
if (timeoutRef.current) {
|
|
281
|
+
clearTimeout(timeoutRef.current);
|
|
282
|
+
}
|
|
283
|
+
const newValue = newNumber
|
|
284
|
+
? { number: newNumber, comparator: newComparator }
|
|
285
|
+
: null;
|
|
286
|
+
if (delay > 0) {
|
|
287
|
+
timeoutRef.current = setTimeout(() => {
|
|
288
|
+
onChange(newValue);
|
|
289
|
+
onFilter?.(newValue);
|
|
290
|
+
}, delay);
|
|
115
291
|
}
|
|
116
292
|
else {
|
|
117
|
-
onChange(
|
|
293
|
+
onChange(newValue);
|
|
294
|
+
onFilter?.(newValue);
|
|
118
295
|
}
|
|
119
|
-
}, [onChange]);
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
296
|
+
}, [onChange, onFilter, delay]);
|
|
297
|
+
// Cleanup timeout on unmount
|
|
298
|
+
useEffect(() => {
|
|
299
|
+
return () => {
|
|
300
|
+
if (timeoutRef.current) {
|
|
301
|
+
clearTimeout(timeoutRef.current);
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
}, []);
|
|
305
|
+
const comparatorSymbols = {
|
|
306
|
+
'=': '=',
|
|
307
|
+
'!=': '≠',
|
|
308
|
+
'>': '>',
|
|
309
|
+
'>=': '≥',
|
|
310
|
+
'<': '<',
|
|
311
|
+
'<=': '≤',
|
|
312
|
+
};
|
|
313
|
+
const inputProps = {
|
|
314
|
+
type: 'text',
|
|
315
|
+
id,
|
|
316
|
+
value: number,
|
|
317
|
+
onChange: (e) => {
|
|
318
|
+
const val = e.target.value;
|
|
319
|
+
const pattern = allowDecimal ? /^[0-9.,]*$/ : /^[0-9]*$/;
|
|
320
|
+
if (pattern.test(val)) {
|
|
321
|
+
handleChange(val, comparator);
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
placeholder: placeholder || column.filterPlaceholder || 'Number...',
|
|
325
|
+
disabled,
|
|
326
|
+
};
|
|
327
|
+
return (_jsxs(FilterContainer, { children: [!hideComparator && (_jsx(ComparatorSelect, { value: comparator, onChange: (e) => handleChange(number, e.target.value), disabled: disabled, children: comparators.map((comp) => (_jsx("option", { value: comp, children: comparatorSymbols[comp] || comp }, comp))) })), className ? (_jsx("input", { ...inputProps, className: className, style: { flex: 1, width: '100%', ...style } })) : (_jsx(FilterInputBase, { ...inputProps, style: { flex: 1, ...style } }))] }));
|
|
126
328
|
};
|
|
329
|
+
export function NumberFilter(optionsOrProps) {
|
|
330
|
+
if (!('column' in optionsOrProps) &&
|
|
331
|
+
!('value' in optionsOrProps) &&
|
|
332
|
+
!('onChange' in optionsOrProps)) {
|
|
333
|
+
const options = optionsOrProps;
|
|
334
|
+
const FilterWithOptions = (props) => (_jsx(NumberFilterComponent, { ...props, options: options }));
|
|
335
|
+
FilterWithOptions.displayName = 'NumberFilter';
|
|
336
|
+
return FilterWithOptions;
|
|
337
|
+
}
|
|
338
|
+
const props = optionsOrProps;
|
|
339
|
+
return _jsx(NumberFilterComponent, { ...props });
|
|
340
|
+
}
|
|
127
341
|
/**
|
|
128
|
-
* Date filter component
|
|
342
|
+
* Internal Date filter component with options support
|
|
129
343
|
*/
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
const [
|
|
133
|
-
const [
|
|
134
|
-
const [
|
|
344
|
+
const DateFilterComponent = ({ column, value, onChange, options }) => {
|
|
345
|
+
const { className, style, defaultValue, defaultComparator = '=', defaultRangeMode = false, getFilter, onFilter, id, disabled, minDate, maxDate, } = options || {};
|
|
346
|
+
const [startDate, setStartDate] = useState(value?.startDate || defaultValue?.startDate || '');
|
|
347
|
+
const [endDate, setEndDate] = useState(value?.endDate || defaultValue?.endDate || '');
|
|
348
|
+
const [diffFlag, setDiffFlag] = useState(value?.diffFlag ?? defaultValue?.diffFlag ?? defaultRangeMode);
|
|
349
|
+
const [comparator, setComparator] = useState(value?.comparator || defaultValue?.comparator || defaultComparator);
|
|
350
|
+
const stateRef = useRef({ startDate, endDate, diffFlag, comparator });
|
|
351
|
+
// Keep ref in sync with state
|
|
352
|
+
useEffect(() => {
|
|
353
|
+
stateRef.current = { startDate, endDate, diffFlag, comparator };
|
|
354
|
+
}, [startDate, endDate, diffFlag, comparator]);
|
|
355
|
+
// Sync with external value changes
|
|
356
|
+
useEffect(() => {
|
|
357
|
+
if (value) {
|
|
358
|
+
setStartDate(value.startDate || '');
|
|
359
|
+
setEndDate(value.endDate || '');
|
|
360
|
+
setDiffFlag(value.diffFlag ?? defaultRangeMode);
|
|
361
|
+
setComparator(value.comparator || defaultComparator);
|
|
362
|
+
}
|
|
363
|
+
}, [value, defaultRangeMode, defaultComparator]);
|
|
364
|
+
// Provide filter instance via getFilter callback - only on mount
|
|
365
|
+
useEffect(() => {
|
|
366
|
+
if (getFilter) {
|
|
367
|
+
getFilter({
|
|
368
|
+
get value() {
|
|
369
|
+
const { startDate: s, endDate: e, diffFlag: d, comparator: c, } = stateRef.current;
|
|
370
|
+
return s || e
|
|
371
|
+
? { startDate: s, endDate: e, diffFlag: d, comparator: c }
|
|
372
|
+
: null;
|
|
373
|
+
},
|
|
374
|
+
setValue: (newValue) => {
|
|
375
|
+
if (newValue) {
|
|
376
|
+
setStartDate(newValue.startDate || '');
|
|
377
|
+
setEndDate(newValue.endDate || '');
|
|
378
|
+
setDiffFlag(newValue.diffFlag ?? defaultRangeMode);
|
|
379
|
+
setComparator(newValue.comparator || defaultComparator);
|
|
380
|
+
onChange(newValue);
|
|
381
|
+
onFilter?.(newValue);
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
setStartDate('');
|
|
385
|
+
setEndDate('');
|
|
386
|
+
onChange(null);
|
|
387
|
+
onFilter?.(null);
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
clear: () => {
|
|
391
|
+
setStartDate('');
|
|
392
|
+
setEndDate('');
|
|
393
|
+
setDiffFlag(defaultRangeMode);
|
|
394
|
+
setComparator(defaultComparator);
|
|
395
|
+
onChange(null);
|
|
396
|
+
onFilter?.(null);
|
|
397
|
+
},
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
401
|
+
}, [getFilter]);
|
|
135
402
|
const handleChange = useCallback((updates) => {
|
|
136
403
|
const newValue = {
|
|
137
404
|
startDate,
|
|
@@ -150,19 +417,90 @@ export const DateFilter = ({ column, value, onChange, }) => {
|
|
|
150
417
|
setComparator(updates.comparator);
|
|
151
418
|
if (newValue.startDate || newValue.endDate) {
|
|
152
419
|
onChange(newValue);
|
|
420
|
+
onFilter?.(newValue);
|
|
153
421
|
}
|
|
154
422
|
else {
|
|
155
423
|
onChange(null);
|
|
424
|
+
onFilter?.(null);
|
|
156
425
|
}
|
|
157
|
-
}, [startDate, endDate, diffFlag, comparator, onChange]);
|
|
158
|
-
return (_jsxs(FilterContainer, { children: [_jsx(ToggleButton, { "$active": diffFlag, onClick: () => handleChange({ diffFlag: !diffFlag }), title: "Date range mode", children: diffFlag ? 'Range' : 'Single' }), !diffFlag && (_jsxs(ComparatorSelect, { value: comparator, onChange: (e) => handleChange({ comparator: e.target.value }), children: [_jsx("option", { value: "=", children: "=" }), _jsx("option", { value: ">=", children: "\u2265" }), _jsx("option", { value: "<", children: "<" })] })), _jsx(DateInput, { type: "date", value: startDate, onChange: (e) => handleChange({ startDate: e.target.value }) }), diffFlag && (_jsxs(_Fragment, { children: [_jsx("span", { style: { color: '#6b7280', fontSize: 12 }, children: "to" }), _jsx(DateInput, { type: "date", value: endDate, onChange: (e) => handleChange({ endDate: e.target.value }) })] }))] }));
|
|
426
|
+
}, [startDate, endDate, diffFlag, comparator, onChange, onFilter]);
|
|
427
|
+
return (_jsxs(FilterContainer, { className: className, style: style, children: [_jsx(ToggleButton, { "$active": diffFlag, onClick: () => handleChange({ diffFlag: !diffFlag }), title: "Date range mode", disabled: disabled, children: diffFlag ? 'Range' : 'Single' }), !diffFlag && (_jsxs(ComparatorSelect, { value: comparator, onChange: (e) => handleChange({ comparator: e.target.value }), disabled: disabled, children: [_jsx("option", { value: "=", children: "=" }), _jsx("option", { value: ">=", children: "\u2265" }), _jsx("option", { value: "<", children: "<" })] })), _jsx(DateInput, { type: "date", id: id, value: startDate, onChange: (e) => handleChange({ startDate: e.target.value }), disabled: disabled, min: minDate, max: maxDate }), diffFlag && (_jsxs(_Fragment, { children: [_jsx("span", { style: { color: '#6b7280', fontSize: 12 }, children: "to" }), _jsx(DateInput, { type: "date", value: endDate, onChange: (e) => handleChange({ endDate: e.target.value }), disabled: disabled, min: minDate, max: maxDate })] }))] }));
|
|
159
428
|
};
|
|
429
|
+
export function DateFilter(optionsOrProps) {
|
|
430
|
+
if (!('column' in optionsOrProps) &&
|
|
431
|
+
!('value' in optionsOrProps) &&
|
|
432
|
+
!('onChange' in optionsOrProps)) {
|
|
433
|
+
const options = optionsOrProps;
|
|
434
|
+
const FilterWithOptions = (props) => (_jsx(DateFilterComponent, { ...props, options: options }));
|
|
435
|
+
FilterWithOptions.displayName = 'DateFilter';
|
|
436
|
+
return FilterWithOptions;
|
|
437
|
+
}
|
|
438
|
+
const props = optionsOrProps;
|
|
439
|
+
return _jsx(DateFilterComponent, { ...props });
|
|
440
|
+
}
|
|
160
441
|
/**
|
|
161
|
-
* Select filter component
|
|
442
|
+
* Internal Select filter component with options support
|
|
162
443
|
*/
|
|
163
|
-
|
|
164
|
-
|
|
444
|
+
const SelectFilterComponent = ({ column, value, onChange, options }) => {
|
|
445
|
+
const { placeholder = 'All', className, style, defaultValue, options: customOptions, getFilter, onFilter, id, disabled, } = options || {};
|
|
446
|
+
const [selectedValue, setSelectedValue] = useState(value || defaultValue || '');
|
|
447
|
+
const selectedValueRef = useRef(selectedValue);
|
|
448
|
+
// Keep ref in sync with state
|
|
449
|
+
useEffect(() => {
|
|
450
|
+
selectedValueRef.current = selectedValue;
|
|
451
|
+
}, [selectedValue]);
|
|
452
|
+
// Sync with external value changes
|
|
453
|
+
useEffect(() => {
|
|
454
|
+
setSelectedValue(value || '');
|
|
455
|
+
}, [value]);
|
|
456
|
+
// Provide filter instance via getFilter callback - only on mount
|
|
457
|
+
useEffect(() => {
|
|
458
|
+
if (getFilter) {
|
|
459
|
+
getFilter({
|
|
460
|
+
get value() {
|
|
461
|
+
return selectedValueRef.current || null;
|
|
462
|
+
},
|
|
463
|
+
setValue: (newValue) => {
|
|
464
|
+
setSelectedValue(newValue || '');
|
|
465
|
+
onChange(newValue);
|
|
466
|
+
onFilter?.(newValue);
|
|
467
|
+
},
|
|
468
|
+
clear: () => {
|
|
469
|
+
setSelectedValue('');
|
|
470
|
+
onChange(null);
|
|
471
|
+
onFilter?.(null);
|
|
472
|
+
},
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
476
|
+
}, [getFilter]);
|
|
477
|
+
const handleChange = useCallback((e) => {
|
|
478
|
+
const newValue = e.target.value || null;
|
|
479
|
+
setSelectedValue(e.target.value);
|
|
480
|
+
onChange(newValue);
|
|
481
|
+
onFilter?.(newValue);
|
|
482
|
+
}, [onChange, onFilter]);
|
|
483
|
+
// Use custom options if provided, otherwise fall back to column.filterOptions
|
|
484
|
+
const selectOptions = customOptions || column.filterOptions || [];
|
|
485
|
+
const selectContent = (_jsxs(_Fragment, { children: [_jsx("option", { value: "", children: placeholder }), selectOptions.map((opt) => (_jsx("option", { value: opt.value, children: opt.label }, opt.value)))] }));
|
|
486
|
+
// If custom className is provided, use plain select to allow full CSS control
|
|
487
|
+
if (className) {
|
|
488
|
+
return (_jsx("select", { id: id, value: selectedValue, onChange: handleChange, className: className, style: { width: '100%', ...style }, disabled: disabled, children: selectContent }));
|
|
489
|
+
}
|
|
490
|
+
return (_jsx(FilterSelectBase, { id: id, value: selectedValue, onChange: handleChange, style: style, disabled: disabled, children: selectContent }));
|
|
165
491
|
};
|
|
492
|
+
export function SelectFilter(optionsOrProps) {
|
|
493
|
+
if (!('column' in optionsOrProps) &&
|
|
494
|
+
!('value' in optionsOrProps) &&
|
|
495
|
+
!('onChange' in optionsOrProps)) {
|
|
496
|
+
const options = optionsOrProps;
|
|
497
|
+
const FilterWithOptions = (props) => (_jsx(SelectFilterComponent, { ...props, options: options }));
|
|
498
|
+
FilterWithOptions.displayName = 'SelectFilter';
|
|
499
|
+
return FilterWithOptions;
|
|
500
|
+
}
|
|
501
|
+
const props = optionsOrProps;
|
|
502
|
+
return _jsx(SelectFilterComponent, { ...props });
|
|
503
|
+
}
|
|
166
504
|
/**
|
|
167
505
|
* Get filter component based on type
|
|
168
506
|
*/
|
|
@@ -2,4 +2,5 @@ export { Table, default } from './Table';
|
|
|
2
2
|
export * from './types';
|
|
3
3
|
export { useSortState, useFilterState, usePaginationState, useRowSelection, useRowExpansion, useColumnVisibility, useTableDebounce, sortData, filterData, paginateData, getNestedValue, exportToCSV, } from './hooks';
|
|
4
4
|
export { TextFilter, NumberFilter, DateFilter, SelectFilter, getFilterComponent, } from './filters';
|
|
5
|
+
export type { TextFilterOptions, TextFilterInstance, NumberFilterOptions, NumberFilterInstance, SelectFilterOptions, SelectFilterInstance, DateFilterOptions, DateFilterInstance, } from './filters';
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/core-components/src/components/Table/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAE,OAAO,EAAC,MAAM,SAAS,CAAC;AACvC,cAAc,SAAS,CAAC;AACxB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,cAAc,EACd,WAAW,GACZ,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,UAAU,EACV,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,kBAAkB,GACnB,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/core-components/src/components/Table/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAE,OAAO,EAAC,MAAM,SAAS,CAAC;AACvC,cAAc,SAAS,CAAC;AACxB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,cAAc,EACd,WAAW,GACZ,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,UAAU,EACV,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,kBAAkB,GACnB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,WAAW,CAAC"}
|
|
@@ -77,8 +77,8 @@ export interface TableColumn<T = any> {
|
|
|
77
77
|
defaultSort?: SortDirection;
|
|
78
78
|
/** Custom sort caret renderer */
|
|
79
79
|
sortCaret?: (order: SortDirection, column: TableColumn<T>) => React.ReactNode;
|
|
80
|
-
/** Whether column is filterable */
|
|
81
|
-
filter?: boolean
|
|
80
|
+
/** Whether column is filterable, or a custom filter component */
|
|
81
|
+
filter?: boolean | React.ComponentType<TableFilterProps>;
|
|
82
82
|
/** Filter type */
|
|
83
83
|
filterType?: FilterType;
|
|
84
84
|
/** Filter options (for select filter) */
|
|
@@ -86,7 +86,7 @@ export interface TableColumn<T = any> {
|
|
|
86
86
|
value: string;
|
|
87
87
|
label: string;
|
|
88
88
|
}>;
|
|
89
|
-
/** Custom filter component */
|
|
89
|
+
/** Custom filter component (alias for filter when using component) */
|
|
90
90
|
filterComponent?: React.ComponentType<TableFilterProps>;
|
|
91
91
|
/** Custom filter renderer */
|
|
92
92
|
filterRenderer?: (onFilter: (value: any) => void, column: TableColumn<T>) => React.ReactNode;
|
|
@@ -121,6 +121,14 @@ export interface TableColumn<T = any> {
|
|
|
121
121
|
csvExport?: boolean;
|
|
122
122
|
/** Header CSS class */
|
|
123
123
|
headerClasses?: string;
|
|
124
|
+
/** Hide header text/title (only show filter and sort) - deprecated, use isHeaderTitle instead */
|
|
125
|
+
hideHeaderText?: boolean;
|
|
126
|
+
/** Show/hide header title (default: true) */
|
|
127
|
+
isHeaderTitle?: boolean;
|
|
128
|
+
/** Show/hide header filter component (default: true) */
|
|
129
|
+
isHeaderFilterComp?: boolean;
|
|
130
|
+
/** Show/hide header sort icon (default: true) */
|
|
131
|
+
isHeaderSort?: boolean;
|
|
124
132
|
/** Cell CSS class */
|
|
125
133
|
classes?: string | ((cell: any, row: T, rowIndex: number, colIndex: number) => string);
|
|
126
134
|
/** Header style */
|
|
@@ -334,6 +342,14 @@ export interface TableProps<T = any> {
|
|
|
334
342
|
defaultFilters?: TableFilterState;
|
|
335
343
|
/** Controlled filters */
|
|
336
344
|
filters?: TableFilterState;
|
|
345
|
+
/** Show filter row by default (when filterable is true) */
|
|
346
|
+
defaultShowFilters?: boolean;
|
|
347
|
+
/** Controlled show/hide filter row */
|
|
348
|
+
showFilters?: boolean;
|
|
349
|
+
/** Callback when filter visibility changes */
|
|
350
|
+
onShowFiltersChange?: (visible: boolean) => void;
|
|
351
|
+
/** Show filter toggle button in toolbar */
|
|
352
|
+
showFilterToggle?: boolean;
|
|
337
353
|
/** Enable global search */
|
|
338
354
|
searchable?: boolean;
|
|
339
355
|
/** Search placeholder */
|
|
@@ -370,6 +386,8 @@ export interface TableProps<T = any> {
|
|
|
370
386
|
hover?: boolean;
|
|
371
387
|
/** Compact/dense mode */
|
|
372
388
|
compact?: boolean;
|
|
389
|
+
/** Custom cell padding (e.g., '2px', '4px 6px'). Default is '2px' */
|
|
390
|
+
cellPadding?: string;
|
|
373
391
|
/** Fixed header */
|
|
374
392
|
stickyHeader?: boolean;
|
|
375
393
|
/** Table max height (for sticky header) */
|