@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xcelsior/ui-spreadsheets",
3
- "version": "1.1.7",
3
+ "version": "1.1.8",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "dependencies": {
@@ -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 */