@xcelsior/ui-spreadsheets 1.1.7 → 1.1.8
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 +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +26 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +26 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/Spreadsheet.stories.tsx +56 -0
- package/src/components/Spreadsheet.tsx +9 -0
- package/src/hooks/useSpreadsheetPinning.ts +30 -0
- package/src/types.ts +4 -1
package/package.json
CHANGED
|
@@ -1511,3 +1511,59 @@ export const WithCheckboxColumns: Story = {
|
|
|
1511
1511
|
);
|
|
1512
1512
|
},
|
|
1513
1513
|
};
|
|
1514
|
+
|
|
1515
|
+
// With Right-Pinned Columns
|
|
1516
|
+
export const WithRightPinnedColumns: Story = {
|
|
1517
|
+
render: () => {
|
|
1518
|
+
const [data, setData] = useState(sampleUsers);
|
|
1519
|
+
|
|
1520
|
+
const handleCellsEdit = (edits: CellEdit[]) => {
|
|
1521
|
+
setData((prev) =>
|
|
1522
|
+
prev.map((row) => {
|
|
1523
|
+
const editsForRow = edits.filter((e) => e.rowId === row.id);
|
|
1524
|
+
if (editsForRow.length > 0) {
|
|
1525
|
+
const updates = editsForRow.reduce(
|
|
1526
|
+
(acc, edit) => ({ ...acc, [edit.columnId]: edit.value }),
|
|
1527
|
+
{}
|
|
1528
|
+
);
|
|
1529
|
+
return { ...row, ...updates };
|
|
1530
|
+
}
|
|
1531
|
+
return row;
|
|
1532
|
+
})
|
|
1533
|
+
);
|
|
1534
|
+
};
|
|
1535
|
+
|
|
1536
|
+
return (
|
|
1537
|
+
<div className="p-4">
|
|
1538
|
+
<div className="mb-4 p-4 bg-purple-50 rounded-lg border border-purple-200">
|
|
1539
|
+
<h3 className="font-semibold text-purple-900 mb-2">Right-Pinned Columns Demo</h3>
|
|
1540
|
+
<p className="text-sm text-purple-700 mb-3">
|
|
1541
|
+
This example demonstrates columns pinned to the right side of the spreadsheet.
|
|
1542
|
+
The "Status" and "Active" columns are pinned to the right and will remain visible
|
|
1543
|
+
when scrolling horizontally.
|
|
1544
|
+
</p>
|
|
1545
|
+
<ul className="text-sm text-purple-700 space-y-1 ml-4 list-disc">
|
|
1546
|
+
<li><strong>ID column</strong> is pinned to the left</li>
|
|
1547
|
+
<li><strong>Status and Active columns</strong> are pinned to the right</li>
|
|
1548
|
+
<li>Scroll horizontally to see the pinned columns stay in place</li>
|
|
1549
|
+
</ul>
|
|
1550
|
+
</div>
|
|
1551
|
+
|
|
1552
|
+
<Spreadsheet
|
|
1553
|
+
data={data}
|
|
1554
|
+
columns={userColumns}
|
|
1555
|
+
getRowId={(row) => row.id}
|
|
1556
|
+
onCellsEdit={handleCellsEdit}
|
|
1557
|
+
settings={{
|
|
1558
|
+
defaultPinnedColumns: ['id'],
|
|
1559
|
+
defaultPinnedRightColumns: ['status', 'isActive'],
|
|
1560
|
+
}}
|
|
1561
|
+
showToolbar
|
|
1562
|
+
showPagination
|
|
1563
|
+
enableRowSelection
|
|
1564
|
+
enableCellEditing
|
|
1565
|
+
/>
|
|
1566
|
+
</div>
|
|
1567
|
+
);
|
|
1568
|
+
},
|
|
1569
|
+
};
|
|
@@ -188,12 +188,14 @@ export function Spreadsheet<T extends Record<string, any>>({
|
|
|
188
188
|
handleToggleGroupCollapse,
|
|
189
189
|
setPinnedColumnsFromIds,
|
|
190
190
|
getColumnLeftOffset,
|
|
191
|
+
getColumnRightOffset,
|
|
191
192
|
isColumnPinned,
|
|
192
193
|
getColumnPinSide,
|
|
193
194
|
} = useSpreadsheetPinning({
|
|
194
195
|
columns,
|
|
195
196
|
columnGroups,
|
|
196
197
|
defaultPinnedColumns: initialSettings?.defaultPinnedColumns,
|
|
198
|
+
defaultPinnedRightColumns: initialSettings?.defaultPinnedRightColumns,
|
|
197
199
|
});
|
|
198
200
|
|
|
199
201
|
// Comments hook
|
|
@@ -755,6 +757,9 @@ export function Spreadsheet<T extends Record<string, any>>({
|
|
|
755
757
|
const isPinnedLeft =
|
|
756
758
|
isColumnPinned(column.id) &&
|
|
757
759
|
getColumnPinSide(column.id) === 'left';
|
|
760
|
+
const isPinnedRight =
|
|
761
|
+
isColumnPinned(column.id) &&
|
|
762
|
+
getColumnPinSide(column.id) === 'right';
|
|
758
763
|
return (
|
|
759
764
|
<SpreadsheetHeader
|
|
760
765
|
key={column.id}
|
|
@@ -766,6 +771,9 @@ export function Spreadsheet<T extends Record<string, any>>({
|
|
|
766
771
|
leftOffset={
|
|
767
772
|
isPinnedLeft ? getColumnLeftOffset(column.id) : 0
|
|
768
773
|
}
|
|
774
|
+
rightOffset={
|
|
775
|
+
isPinnedRight ? getColumnRightOffset(column.id) : 0
|
|
776
|
+
}
|
|
769
777
|
highlightColor={getColumnHighlight(column.id)}
|
|
770
778
|
compactMode={effectiveCompactMode}
|
|
771
779
|
onClick={() => handleSort(column.id)}
|
|
@@ -1047,6 +1055,7 @@ export function Spreadsheet<T extends Record<string, any>>({
|
|
|
1047
1055
|
isPinned={isColPinned}
|
|
1048
1056
|
pinSide={colPinSide}
|
|
1049
1057
|
leftOffset={getColumnLeftOffset(column.id)}
|
|
1058
|
+
rightOffset={getColumnRightOffset(column.id)}
|
|
1050
1059
|
onClick={(e) =>
|
|
1051
1060
|
handleCellClick(rowId, column.id, e)
|
|
1052
1061
|
}
|
|
@@ -10,6 +10,7 @@ export interface UseSpreadsheetPinningOptions<T> {
|
|
|
10
10
|
columnGroups?: SpreadsheetColumnGroup[];
|
|
11
11
|
showRowIndex?: boolean;
|
|
12
12
|
defaultPinnedColumns?: string[];
|
|
13
|
+
defaultPinnedRightColumns?: string[];
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export interface UseSpreadsheetPinningReturn<T> {
|
|
@@ -30,6 +31,7 @@ export interface UseSpreadsheetPinningReturn<T> {
|
|
|
30
31
|
|
|
31
32
|
// Offset calculations
|
|
32
33
|
getColumnLeftOffset: (columnId: string) => number;
|
|
34
|
+
getColumnRightOffset: (columnId: string) => number;
|
|
33
35
|
|
|
34
36
|
// Utility
|
|
35
37
|
isColumnPinned: (columnId: string) => boolean;
|
|
@@ -41,6 +43,7 @@ export function useSpreadsheetPinning<T>({
|
|
|
41
43
|
columnGroups,
|
|
42
44
|
showRowIndex = true,
|
|
43
45
|
defaultPinnedColumns = [],
|
|
46
|
+
defaultPinnedRightColumns = [],
|
|
44
47
|
}: UseSpreadsheetPinningOptions<T>): UseSpreadsheetPinningReturn<T> {
|
|
45
48
|
// Initialize pinned columns from defaults (including row index)
|
|
46
49
|
const [pinnedColumns, setPinnedColumns] = useState<Map<string, 'left' | 'right'>>(() => {
|
|
@@ -48,6 +51,9 @@ export function useSpreadsheetPinning<T>({
|
|
|
48
51
|
defaultPinnedColumns.forEach((col) => {
|
|
49
52
|
map.set(col, 'left');
|
|
50
53
|
});
|
|
54
|
+
defaultPinnedRightColumns.forEach((col) => {
|
|
55
|
+
map.set(col, 'right');
|
|
56
|
+
});
|
|
51
57
|
return map;
|
|
52
58
|
});
|
|
53
59
|
|
|
@@ -196,6 +202,29 @@ export function useSpreadsheetPinning<T>({
|
|
|
196
202
|
[pinnedColumns]
|
|
197
203
|
);
|
|
198
204
|
|
|
205
|
+
// Calculate column offset for right sticky positioning
|
|
206
|
+
const getColumnRightOffset = useCallback(
|
|
207
|
+
(columnId: string): number => {
|
|
208
|
+
// Get right-pinned columns
|
|
209
|
+
const pinnedRight = Array.from(pinnedColumns.entries())
|
|
210
|
+
.filter(([, side]) => side === 'right')
|
|
211
|
+
.map(([id]) => id);
|
|
212
|
+
|
|
213
|
+
const index = pinnedRight.indexOf(columnId);
|
|
214
|
+
if (index === -1) return 0;
|
|
215
|
+
|
|
216
|
+
// Calculate offset from the right edge
|
|
217
|
+
// Start from 0 and add widths of columns to the right of this one
|
|
218
|
+
let offset = 0;
|
|
219
|
+
for (let i = pinnedRight.length - 1; i > index; i--) {
|
|
220
|
+
const col = columns.find((c) => c.id === pinnedRight[i]);
|
|
221
|
+
offset += col?.minWidth || col?.width || 100;
|
|
222
|
+
}
|
|
223
|
+
return offset;
|
|
224
|
+
},
|
|
225
|
+
[pinnedColumns, columns]
|
|
226
|
+
);
|
|
227
|
+
|
|
199
228
|
return {
|
|
200
229
|
pinnedColumns,
|
|
201
230
|
isRowIndexPinned,
|
|
@@ -205,6 +234,7 @@ export function useSpreadsheetPinning<T>({
|
|
|
205
234
|
handleToggleGroupCollapse,
|
|
206
235
|
setPinnedColumnsFromIds,
|
|
207
236
|
getColumnLeftOffset,
|
|
237
|
+
getColumnRightOffset,
|
|
208
238
|
isColumnPinned,
|
|
209
239
|
getColumnPinSide,
|
|
210
240
|
};
|
package/src/types.ts
CHANGED
|
@@ -385,8 +385,10 @@ export interface SpreadsheetProps<T = any> {
|
|
|
385
385
|
onSave?: () => void | Promise<void>;
|
|
386
386
|
/** Initial settings (optional). All settings can be changed by user in the settings modal. */
|
|
387
387
|
settings?: {
|
|
388
|
-
/** Default pinned column IDs */
|
|
388
|
+
/** Default pinned column IDs (pinned to left) */
|
|
389
389
|
defaultPinnedColumns?: string[];
|
|
390
|
+
/** Default pinned column IDs (pinned to right) */
|
|
391
|
+
defaultPinnedRightColumns?: string[];
|
|
390
392
|
/** Default sort configuration */
|
|
391
393
|
defaultSort?: SpreadsheetSortConfig | null;
|
|
392
394
|
/** Default page size */
|
|
@@ -405,6 +407,7 @@ export interface SpreadsheetProps<T = any> {
|
|
|
405
407
|
defaultPageSize?: number;
|
|
406
408
|
defaultZoom?: number;
|
|
407
409
|
defaultPinnedColumns?: string[];
|
|
410
|
+
defaultPinnedRightColumns?: string[];
|
|
408
411
|
defaultSort?: SpreadsheetSortConfig | null;
|
|
409
412
|
}) => void;
|
|
410
413
|
/** Loading state */
|