@xcelsior/ui-spreadsheets 1.1.14 → 1.1.16
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/dist/index.d.mts +28 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +659 -401
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +652 -395
- package/dist/index.mjs.map +1 -1
- package/dist/styles/globals.css +58 -0
- package/dist/styles/globals.css.map +1 -1
- package/package.json +1 -1
- package/src/components/ActiveFiltersDisplay.tsx +257 -0
- package/src/components/Spreadsheet.tsx +39 -5
- package/src/components/SpreadsheetCell.tsx +8 -2
- package/src/components/SpreadsheetHeader.tsx +8 -2
- package/src/components/SpreadsheetToolbar.tsx +249 -203
- package/src/hooks/useSpreadsheetPinning.ts +1 -1
- package/src/index.ts +2 -0
- package/src/types.ts +10 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import {
|
|
3
3
|
HiCheck,
|
|
4
|
+
HiChevronDown,
|
|
5
|
+
HiChevronUp,
|
|
4
6
|
HiCog,
|
|
5
7
|
HiDotsVertical,
|
|
6
8
|
HiFilter,
|
|
@@ -12,6 +14,7 @@ import {
|
|
|
12
14
|
} from 'react-icons/hi';
|
|
13
15
|
import { cn } from '../utils';
|
|
14
16
|
import type { SpreadsheetToolbarProps } from '../types';
|
|
17
|
+
import { ActiveFiltersDisplay } from './ActiveFiltersDisplay';
|
|
15
18
|
|
|
16
19
|
/**
|
|
17
20
|
* SpreadsheetToolbar component - Top toolbar with zoom controls, undo/redo, filters, and actions.
|
|
@@ -60,6 +63,11 @@ export const SpreadsheetToolbar: React.FC<SpreadsheetToolbarProps> = ({
|
|
|
60
63
|
onShowShortcuts,
|
|
61
64
|
hasActiveFilters,
|
|
62
65
|
onClearFilters,
|
|
66
|
+
filters,
|
|
67
|
+
columns,
|
|
68
|
+
onClearFilter,
|
|
69
|
+
showFiltersPanel,
|
|
70
|
+
onToggleFiltersPanel,
|
|
63
71
|
className,
|
|
64
72
|
}) => {
|
|
65
73
|
const [showMoreMenu, setShowMoreMenu] = React.useState(false);
|
|
@@ -122,234 +130,272 @@ export const SpreadsheetToolbar: React.FC<SpreadsheetToolbarProps> = ({
|
|
|
122
130
|
}
|
|
123
131
|
};
|
|
124
132
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
className={cn(
|
|
141
|
-
buttonBaseClasses,
|
|
142
|
-
canUndo
|
|
143
|
-
? 'bg-gray-100 text-gray-700 hover:bg-gray-200'
|
|
144
|
-
: 'bg-gray-50 text-gray-400'
|
|
145
|
-
)}
|
|
146
|
-
title={`Undo (${undoCount} changes)`}
|
|
147
|
-
>
|
|
148
|
-
<HiReply className="h-4 w-4" />
|
|
149
|
-
</button>
|
|
150
|
-
<button
|
|
151
|
-
type={'button'}
|
|
152
|
-
onClick={onRedo}
|
|
153
|
-
disabled={!canRedo}
|
|
154
|
-
className={cn(
|
|
155
|
-
buttonBaseClasses,
|
|
156
|
-
canRedo
|
|
157
|
-
? 'bg-gray-100 text-gray-700 hover:bg-gray-200'
|
|
158
|
-
: 'bg-gray-50 text-gray-400'
|
|
159
|
-
)}
|
|
160
|
-
title={`Redo (${redoCount} changes)`}
|
|
161
|
-
style={{ transform: 'scaleX(-1)' }}
|
|
162
|
-
>
|
|
163
|
-
<HiReply className="h-4 w-4" />
|
|
164
|
-
</button>
|
|
165
|
-
</div>
|
|
133
|
+
// Count active filters
|
|
134
|
+
const activeFilterCount = filters
|
|
135
|
+
? Object.values(filters).filter(
|
|
136
|
+
(f) =>
|
|
137
|
+
f.textCondition ||
|
|
138
|
+
f.numberCondition ||
|
|
139
|
+
f.dateCondition ||
|
|
140
|
+
f.text ||
|
|
141
|
+
(f.selectedValues && f.selectedValues.length > 0) ||
|
|
142
|
+
f.min !== undefined ||
|
|
143
|
+
f.max !== undefined ||
|
|
144
|
+
f.includeBlanks ||
|
|
145
|
+
f.excludeBlanks
|
|
146
|
+
).length
|
|
147
|
+
: 0;
|
|
166
148
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
onClick={onZoomReset}
|
|
180
|
-
className="px-2 py-0.5 hover:bg-white rounded text-xs min-w-[45px] text-center text-gray-600"
|
|
181
|
-
title="Reset zoom"
|
|
182
|
-
>
|
|
183
|
-
{zoom}%
|
|
184
|
-
</button>
|
|
185
|
-
<button
|
|
186
|
-
type={'button'}
|
|
187
|
-
onClick={onZoomIn}
|
|
188
|
-
className="p-1 hover:bg-white rounded"
|
|
189
|
-
title="Zoom in"
|
|
190
|
-
>
|
|
191
|
-
<HiZoomIn className="h-4 w-4 text-gray-600" />
|
|
192
|
-
</button>
|
|
193
|
-
</div>
|
|
194
|
-
</div>
|
|
195
|
-
|
|
196
|
-
{/* Center section: Status indicators */}
|
|
197
|
-
<div className="flex items-center gap-2 flex-1 min-w-0">
|
|
198
|
-
{/* Selected rows indicator */}
|
|
199
|
-
{selectedRowCount > 0 && (
|
|
200
|
-
<div className="flex items-center gap-2 px-2.5 py-1.5 bg-blue-600 text-white rounded">
|
|
201
|
-
<span className="text-xs font-medium whitespace-nowrap">
|
|
202
|
-
{selectedRowCount} row{selectedRowCount !== 1 ? 's' : ''} selected
|
|
203
|
-
</span>
|
|
149
|
+
return (
|
|
150
|
+
<div className="flex flex-col">
|
|
151
|
+
<div
|
|
152
|
+
className={cn(
|
|
153
|
+
'flex flex-wrap items-center justify-between gap-2 px-4 py-2 border-b border-gray-200 bg-white',
|
|
154
|
+
className
|
|
155
|
+
)}
|
|
156
|
+
>
|
|
157
|
+
{/* Left section: Primary actions */}
|
|
158
|
+
<div className="flex items-center gap-2">
|
|
159
|
+
{/* Undo/Redo buttons */}
|
|
160
|
+
<div className="flex items-center gap-1">
|
|
204
161
|
<button
|
|
205
162
|
type={'button'}
|
|
206
|
-
onClick={
|
|
207
|
-
|
|
208
|
-
|
|
163
|
+
onClick={onUndo}
|
|
164
|
+
disabled={!canUndo}
|
|
165
|
+
className={cn(
|
|
166
|
+
buttonBaseClasses,
|
|
167
|
+
canUndo
|
|
168
|
+
? 'bg-gray-100 text-gray-700 hover:bg-gray-200'
|
|
169
|
+
: 'bg-gray-50 text-gray-400'
|
|
170
|
+
)}
|
|
171
|
+
title={`Undo (${undoCount} changes)`}
|
|
209
172
|
>
|
|
210
|
-
<
|
|
173
|
+
<HiReply className="h-4 w-4" />
|
|
211
174
|
</button>
|
|
212
|
-
</div>
|
|
213
|
-
)}
|
|
214
|
-
|
|
215
|
-
{/* Clear filters button */}
|
|
216
|
-
{hasActiveFilters && onClearFilters && (
|
|
217
|
-
<div className="flex items-center gap-2 px-2.5 py-1.5 bg-amber-500 text-white rounded">
|
|
218
|
-
<HiFilter className="h-3.5 w-3.5" />
|
|
219
|
-
<span className="text-xs font-medium whitespace-nowrap">
|
|
220
|
-
Filters active
|
|
221
|
-
</span>
|
|
222
175
|
<button
|
|
223
176
|
type={'button'}
|
|
224
|
-
onClick={
|
|
225
|
-
|
|
226
|
-
|
|
177
|
+
onClick={onRedo}
|
|
178
|
+
disabled={!canRedo}
|
|
179
|
+
className={cn(
|
|
180
|
+
buttonBaseClasses,
|
|
181
|
+
canRedo
|
|
182
|
+
? 'bg-gray-100 text-gray-700 hover:bg-gray-200'
|
|
183
|
+
: 'bg-gray-50 text-gray-400'
|
|
184
|
+
)}
|
|
185
|
+
title={`Redo (${redoCount} changes)`}
|
|
186
|
+
style={{ transform: 'scaleX(-1)' }}
|
|
227
187
|
>
|
|
228
|
-
<
|
|
188
|
+
<HiReply className="h-4 w-4" />
|
|
229
189
|
</button>
|
|
230
190
|
</div>
|
|
231
|
-
)}
|
|
232
191
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
192
|
+
{/* Zoom controls */}
|
|
193
|
+
<div className="flex items-center gap-1 px-1.5 py-1 bg-gray-100 rounded">
|
|
194
|
+
<button
|
|
195
|
+
type={'button'}
|
|
196
|
+
onClick={onZoomOut}
|
|
197
|
+
className="p-1 hover:bg-white rounded"
|
|
198
|
+
title="Zoom out"
|
|
199
|
+
>
|
|
200
|
+
<HiZoomOut className="h-4 w-4 text-gray-600" />
|
|
201
|
+
</button>
|
|
202
|
+
<button
|
|
203
|
+
type={'button'}
|
|
204
|
+
onClick={onZoomReset}
|
|
205
|
+
className="px-2 py-0.5 hover:bg-white rounded text-xs min-w-[45px] text-center text-gray-600"
|
|
206
|
+
title="Reset zoom"
|
|
207
|
+
>
|
|
208
|
+
{zoom}%
|
|
209
|
+
</button>
|
|
210
|
+
<button
|
|
211
|
+
type={'button'}
|
|
212
|
+
onClick={onZoomIn}
|
|
213
|
+
className="p-1 hover:bg-white rounded"
|
|
214
|
+
title="Zoom in"
|
|
215
|
+
>
|
|
216
|
+
<HiZoomIn className="h-4 w-4 text-gray-600" />
|
|
217
|
+
</button>
|
|
243
218
|
</div>
|
|
244
|
-
|
|
245
|
-
</div>
|
|
219
|
+
</div>
|
|
246
220
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
221
|
+
{/* Center section: Status indicators */}
|
|
222
|
+
<div className="flex items-center gap-2 flex-1 min-w-0">
|
|
223
|
+
{/* Selected rows indicator */}
|
|
224
|
+
{selectedRowCount > 0 && (
|
|
225
|
+
<div className="flex items-center gap-2 px-2.5 py-1.5 bg-blue-600 text-white rounded">
|
|
226
|
+
<span className="text-xs font-medium whitespace-nowrap">
|
|
227
|
+
{selectedRowCount} row{selectedRowCount !== 1 ? 's' : ''} selected
|
|
228
|
+
</span>
|
|
229
|
+
<button
|
|
230
|
+
type={'button'}
|
|
231
|
+
onClick={onClearSelection}
|
|
232
|
+
className="p-0.5 hover:bg-blue-700 rounded"
|
|
233
|
+
title="Clear selection"
|
|
234
|
+
>
|
|
235
|
+
<HiX className="h-3 w-3" />
|
|
236
|
+
</button>
|
|
237
|
+
</div>
|
|
238
|
+
)}
|
|
260
239
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
240
|
+
{/* Show filters button */}
|
|
241
|
+
{hasActiveFilters && onToggleFiltersPanel && (
|
|
242
|
+
<button
|
|
243
|
+
type={'button'}
|
|
244
|
+
onClick={onToggleFiltersPanel}
|
|
245
|
+
className={cn(
|
|
246
|
+
'flex items-center gap-2 px-2.5 py-1.5 rounded transition-colors',
|
|
247
|
+
showFiltersPanel
|
|
248
|
+
? 'bg-amber-600 text-white hover:bg-amber-700'
|
|
249
|
+
: 'bg-amber-500 text-white hover:bg-amber-600'
|
|
250
|
+
)}
|
|
251
|
+
title={showFiltersPanel ? 'Hide active filters' : 'Show active filters'}
|
|
252
|
+
>
|
|
253
|
+
<HiFilter className="h-3.5 w-3.5" />
|
|
254
|
+
<span className="text-xs font-medium whitespace-nowrap">
|
|
255
|
+
{activeFilterCount} filter{activeFilterCount !== 1 ? 's' : ''}{' '}
|
|
256
|
+
active
|
|
257
|
+
</span>
|
|
258
|
+
{showFiltersPanel ? (
|
|
259
|
+
<HiChevronUp className="h-3 w-3" />
|
|
260
|
+
) : (
|
|
261
|
+
<HiChevronDown className="h-3 w-3" />
|
|
262
|
+
)}
|
|
263
|
+
</button>
|
|
264
|
+
)}
|
|
276
265
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
266
|
+
{/* Summary badge */}
|
|
267
|
+
{summary && (
|
|
268
|
+
<div
|
|
269
|
+
className={cn(
|
|
270
|
+
'flex items-center gap-2 px-2.5 py-1.5 rounded border text-xs',
|
|
271
|
+
getSummaryVariantClasses(summary.variant)
|
|
272
|
+
)}
|
|
273
|
+
>
|
|
274
|
+
<span className="font-semibold whitespace-nowrap">
|
|
275
|
+
{summary.label}:
|
|
276
|
+
</span>
|
|
277
|
+
<span className="font-bold whitespace-nowrap">{summary.value}</span>
|
|
278
|
+
</div>
|
|
279
|
+
)}
|
|
280
|
+
</div>
|
|
288
281
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
setShowMoreMenu(false);
|
|
298
|
-
}}
|
|
299
|
-
className="w-full px-3 py-2 text-left hover:bg-gray-50 flex items-center gap-2 text-xs transition-colors"
|
|
300
|
-
>
|
|
301
|
-
<HiCog className="h-3.5 w-3.5 text-gray-500" />
|
|
302
|
-
<span className="text-gray-700">Settings</span>
|
|
303
|
-
</button>
|
|
282
|
+
{/* Right section: Action buttons */}
|
|
283
|
+
<div className="flex items-center gap-2">
|
|
284
|
+
{/* Save status */}
|
|
285
|
+
{saveStatusDisplay && (
|
|
286
|
+
<span
|
|
287
|
+
className={cn(
|
|
288
|
+
'text-xs flex items-center gap-1',
|
|
289
|
+
saveStatusDisplay.className
|
|
304
290
|
)}
|
|
291
|
+
>
|
|
292
|
+
{saveStatusDisplay.text}
|
|
293
|
+
</span>
|
|
294
|
+
)}
|
|
305
295
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
<HiOutlineQuestionMarkCircle className="h-3.5 w-3.5 text-gray-500" />
|
|
316
|
-
<span className="text-gray-700">Keyboard Shortcuts</span>
|
|
317
|
-
</button>
|
|
296
|
+
{/* Manual save button (when auto-save is off) */}
|
|
297
|
+
{!autoSave && onSave && (
|
|
298
|
+
<button
|
|
299
|
+
type={'button'}
|
|
300
|
+
onClick={onSave}
|
|
301
|
+
disabled={!hasUnsavedChanges}
|
|
302
|
+
className={cn(
|
|
303
|
+
'px-3 py-1.5 text-xs bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors flex items-center gap-1.5',
|
|
304
|
+
'disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-blue-600'
|
|
318
305
|
)}
|
|
306
|
+
>
|
|
307
|
+
<HiCheck className="h-3.5 w-3.5" />
|
|
308
|
+
Save
|
|
309
|
+
</button>
|
|
310
|
+
)}
|
|
319
311
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
312
|
+
{/* More menu dropdown */}
|
|
313
|
+
<div className="relative" ref={menuRef}>
|
|
314
|
+
<button
|
|
315
|
+
type={'button'}
|
|
316
|
+
onClick={() => setShowMoreMenu(!showMoreMenu)}
|
|
317
|
+
className="px-2.5 py-1.5 bg-gray-100 text-gray-700 rounded hover:bg-gray-200 transition-colors flex items-center gap-1.5 text-xs"
|
|
318
|
+
title="More actions"
|
|
319
|
+
>
|
|
320
|
+
<HiDotsVertical className="h-3.5 w-3.5" />
|
|
321
|
+
<span className="hidden lg:inline">More</span>
|
|
322
|
+
</button>
|
|
323
|
+
|
|
324
|
+
{/* Dropdown Menu */}
|
|
325
|
+
{showMoreMenu && (
|
|
326
|
+
<div className="absolute right-0 top-full mt-1 bg-white border border-gray-200 shadow-lg rounded py-1 min-w-[180px] z-50">
|
|
327
|
+
{onSettings && (
|
|
328
|
+
<button
|
|
329
|
+
type={'button'}
|
|
330
|
+
onClick={() => {
|
|
331
|
+
onSettings();
|
|
332
|
+
setShowMoreMenu(false);
|
|
333
|
+
}}
|
|
334
|
+
className="w-full px-3 py-2 text-left hover:bg-gray-50 flex items-center gap-2 text-xs transition-colors"
|
|
335
|
+
>
|
|
336
|
+
<HiCog className="h-3.5 w-3.5 text-gray-500" />
|
|
337
|
+
<span className="text-gray-700">Settings</span>
|
|
338
|
+
</button>
|
|
325
339
|
)}
|
|
326
340
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
341
|
+
{onShowShortcuts && (
|
|
342
|
+
<button
|
|
343
|
+
type={'button'}
|
|
344
|
+
onClick={() => {
|
|
345
|
+
onShowShortcuts();
|
|
346
|
+
setShowMoreMenu(false);
|
|
347
|
+
}}
|
|
348
|
+
className="w-full px-3 py-2 text-left hover:bg-gray-50 flex items-center gap-2 text-xs transition-colors"
|
|
349
|
+
>
|
|
350
|
+
<HiOutlineQuestionMarkCircle className="h-3.5 w-3.5 text-gray-500" />
|
|
351
|
+
<span className="text-gray-700">Keyboard Shortcuts</span>
|
|
352
|
+
</button>
|
|
353
|
+
)}
|
|
354
|
+
|
|
355
|
+
{/* Custom menu items */}
|
|
356
|
+
{menuItems &&
|
|
357
|
+
menuItems.length > 0 &&
|
|
358
|
+
(onSettings || onShowShortcuts) && (
|
|
359
|
+
<div className="border-t border-gray-100 my-1" />
|
|
345
360
|
)}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
361
|
+
|
|
362
|
+
{menuItems?.map((item) => (
|
|
363
|
+
<button
|
|
364
|
+
key={item.id}
|
|
365
|
+
type={'button'}
|
|
366
|
+
disabled={item.disabled}
|
|
367
|
+
onClick={() => {
|
|
368
|
+
item.onClick();
|
|
369
|
+
setShowMoreMenu(false);
|
|
370
|
+
}}
|
|
371
|
+
className={cn(
|
|
372
|
+
'w-full px-3 py-2 text-left hover:bg-gray-50 flex items-center gap-2 text-xs transition-colors',
|
|
373
|
+
item.disabled && 'opacity-50 cursor-not-allowed'
|
|
374
|
+
)}
|
|
375
|
+
>
|
|
376
|
+
{item.icon && (
|
|
377
|
+
<span className="h-3.5 w-3.5 text-gray-500 flex items-center justify-center">
|
|
378
|
+
{item.icon}
|
|
379
|
+
</span>
|
|
380
|
+
)}
|
|
381
|
+
<span className="text-gray-700">{item.label}</span>
|
|
382
|
+
</button>
|
|
383
|
+
))}
|
|
384
|
+
</div>
|
|
385
|
+
)}
|
|
386
|
+
</div>
|
|
351
387
|
</div>
|
|
352
388
|
</div>
|
|
389
|
+
|
|
390
|
+
{/* Active filters panel */}
|
|
391
|
+
{showFiltersPanel && filters && columns && onClearFilter && onClearFilters && (
|
|
392
|
+
<ActiveFiltersDisplay
|
|
393
|
+
filters={filters}
|
|
394
|
+
columns={columns}
|
|
395
|
+
onClearFilter={onClearFilter}
|
|
396
|
+
onClearAllFilters={onClearFilters}
|
|
397
|
+
/>
|
|
398
|
+
)}
|
|
353
399
|
</div>
|
|
354
400
|
);
|
|
355
401
|
};
|
|
@@ -5,7 +5,7 @@ import type { SpreadsheetColumn, SpreadsheetColumnGroup } from '../types';
|
|
|
5
5
|
export const ROW_INDEX_COLUMN_ID = '__row_index__';
|
|
6
6
|
export const ROW_INDEX_COLUMN_WIDTH = 80;
|
|
7
7
|
// Minimum width for any pinned column to ensure header actions (pin, filter, highlight icons) fit
|
|
8
|
-
export const MIN_PINNED_COLUMN_WIDTH =
|
|
8
|
+
export const MIN_PINNED_COLUMN_WIDTH = 150;
|
|
9
9
|
|
|
10
10
|
export interface UseSpreadsheetPinningOptions<T> {
|
|
11
11
|
columns: SpreadsheetColumn<T>[];
|
package/src/index.ts
CHANGED
|
@@ -8,6 +8,8 @@ export { SpreadsheetFilterDropdown } from './components/SpreadsheetFilterDropdow
|
|
|
8
8
|
export { SpreadsheetToolbar } from './components/SpreadsheetToolbar';
|
|
9
9
|
export { SpreadsheetSettingsModal } from './components/SpreadsheetSettingsModal';
|
|
10
10
|
export { RowContextMenu } from './components/RowContextMenu';
|
|
11
|
+
export { ActiveFiltersDisplay } from './components/ActiveFiltersDisplay';
|
|
12
|
+
export type { ActiveFiltersDisplayProps } from './components/ActiveFiltersDisplay';
|
|
11
13
|
export type { SpreadsheetSettings } from './components/SpreadsheetSettingsModal';
|
|
12
14
|
|
|
13
15
|
// Types
|
package/src/types.ts
CHANGED
|
@@ -703,6 +703,16 @@ export interface SpreadsheetToolbarProps {
|
|
|
703
703
|
hasActiveFilters?: boolean;
|
|
704
704
|
/** Callback to clear all filters */
|
|
705
705
|
onClearFilters?: () => void;
|
|
706
|
+
/** Current filters (for displaying active filters) */
|
|
707
|
+
filters?: Record<string, SpreadsheetColumnFilter>;
|
|
708
|
+
/** Column definitions (for displaying filter column names) */
|
|
709
|
+
columns?: SpreadsheetColumn[];
|
|
710
|
+
/** Callback to clear individual filter */
|
|
711
|
+
onClearFilter?: (columnId: string) => void;
|
|
712
|
+
/** Whether to show the active filters panel */
|
|
713
|
+
showFiltersPanel?: boolean;
|
|
714
|
+
/** Callback to toggle the active filters panel */
|
|
715
|
+
onToggleFiltersPanel?: () => void;
|
|
706
716
|
/** Custom className */
|
|
707
717
|
className?: string;
|
|
708
718
|
}
|