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.
@@ -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: 4px;
10
+ gap: 3px;
11
11
  `;
12
12
  const FilterInputBase = styled.input `
13
13
  width: 100%;
14
- height: 28px;
15
- padding: 0 8px;
16
- font-size: 12px;
17
- border: 1px solid ${tokens.outline || '#d1d5db'};
18
- border-radius: 4px;
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}40` : '#9ca3af'};
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: 28px;
33
- padding: 0 8px;
34
- font-size: 12px;
35
- border: 1px solid ${tokens.outline || '#d1d5db'};
36
- border-radius: 4px;
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: 50px;
47
- height: 28px;
48
- padding: 0 4px;
49
- font-size: 11px;
50
- border: 1px solid ${tokens.outline || '#d1d5db'};
51
- border-radius: 4px;
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: 28px;
64
- padding: 0 8px;
65
- font-size: 12px;
66
- border: 1px solid ${tokens.outline || '#d1d5db'};
67
- border-radius: 4px;
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: 100px;
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: 28px;
78
- padding: 0 8px;
79
- font-size: 11px;
80
- font-weight: 500;
81
- border: 1px solid ${tokens.outline || '#d1d5db'};
82
- border-radius: 4px;
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
- export const TextFilter = ({ column, value, onChange, }) => {
102
- return (_jsx(FilterInputBase, { type: "text", value: value || '', onChange: (e) => onChange(e.target.value), placeholder: column.filterPlaceholder || `Filter ${column.text}...` }));
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 comparator
224
+ * Internal Number filter component with options support
106
225
  */
107
- export const NumberFilter = ({ column, value, onChange, }) => {
108
- const [number, setNumber] = useState(value?.number || '');
109
- const [comparator, setComparator] = useState(value?.comparator || '=');
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 (newNumber) {
114
- onChange({ number: newNumber, comparator: newComparator });
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(null);
293
+ onChange(newValue);
294
+ onFilter?.(newValue);
118
295
  }
119
- }, [onChange]);
120
- return (_jsxs(FilterContainer, { children: [_jsxs(ComparatorSelect, { value: comparator, onChange: (e) => handleChange(number, e.target.value), children: [_jsx("option", { value: "=", children: "=" }), _jsx("option", { value: "!=", children: "\u2260" }), _jsx("option", { value: ">", children: ">" }), _jsx("option", { value: ">=", children: "\u2265" }), _jsx("option", { value: "<", children: "<" }), _jsx("option", { value: "<=", children: "\u2264" })] }), _jsx(FilterInputBase, { type: "text", value: number, onChange: (e) => {
121
- const val = e.target.value;
122
- if (/^[0-9.,]*$/.test(val)) {
123
- handleChange(val, comparator);
124
- }
125
- }, placeholder: column.filterPlaceholder || 'Number...' })] }));
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
- export const DateFilter = ({ column, value, onChange, }) => {
131
- const [startDate, setStartDate] = useState(value?.startDate || '');
132
- const [endDate, setEndDate] = useState(value?.endDate || '');
133
- const [diffFlag, setDiffFlag] = useState(value?.diffFlag || false);
134
- const [comparator, setComparator] = useState(value?.comparator || '=');
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
- export const SelectFilter = ({ column, value, onChange, }) => {
164
- return (_jsxs(FilterSelectBase, { value: value || '', onChange: (e) => onChange(e.target.value || null), children: [_jsx("option", { value: "", children: "All" }), column.filterOptions?.map((opt) => (_jsx("option", { value: opt.value, children: opt.label }, opt.value)))] }));
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) */