@xcelsior/ui-spreadsheets 1.0.4 → 1.0.5

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.0.4",
3
+ "version": "1.0.5",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "dependencies": {
@@ -75,6 +75,8 @@ export interface ViewCommentsModalProps {
75
75
  columnLabel?: string;
76
76
  /** Callback to toggle comment resolved status */
77
77
  onToggleResolved: (commentId: string) => void;
78
+ /** Callback to add a new comment */
79
+ onAddComment?: () => void;
78
80
  /** Callback to close the modal */
79
81
  onClose: () => void;
80
82
  }
@@ -84,6 +86,7 @@ export function ViewCommentsModal({
84
86
  comments,
85
87
  columnLabel,
86
88
  onToggleResolved,
89
+ onAddComment,
87
90
  onClose,
88
91
  }: ViewCommentsModalProps) {
89
92
  if (!isOpen) return null;
@@ -139,6 +142,18 @@ export function ViewCommentsModal({
139
142
  <p className="text-center text-gray-500 py-8">No comments for this cell.</p>
140
143
  )}
141
144
  </div>
145
+ {/* Add Comment button at the bottom */}
146
+ {onAddComment && (
147
+ <div className="mt-4 pt-4 border-t border-gray-200">
148
+ <button
149
+ type="button"
150
+ onClick={onAddComment}
151
+ className="w-full px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors flex items-center justify-center gap-2"
152
+ >
153
+ <span>+ Add Comment</span>
154
+ </button>
155
+ </div>
156
+ )}
142
157
  </div>
143
158
  </div>
144
159
  );
@@ -524,7 +524,7 @@ export const WithHighlightsAndComments: Story = {
524
524
  // Large dataset (performance test)
525
525
  export const LargeDataset: Story = {
526
526
  args: {
527
- data: Array.from({ length: 1000 }, (_, i) => ({
527
+ data: Array.from({ length: 3000 }, (_, i) => ({
528
528
  id: i + 1,
529
529
  name: `User ${i + 1}`,
530
530
  email: `user${i + 1}@example.com`,
@@ -805,62 +805,13 @@ export function Spreadsheet<T extends Record<string, any>>({
805
805
  }),
806
806
  }}
807
807
  >
808
- <div className={'relative'}>
809
- {/* Row number */}
810
- <div className="py-1 px-1">
811
- {displayIndex}
812
- </div>
808
+ <div className="relative flex items-center justify-center">
809
+ {/* Row number - always centered */}
810
+ <span>{displayIndex}</span>
813
811
 
814
- {/* Row index comment indicator */}
815
- {cellHasComments(
816
- rowId,
817
- ROW_INDEX_COLUMN_ID
818
- ) && (
819
- <button
820
- type="button"
821
- onClick={(e) => {
822
- e.stopPropagation();
823
- setViewCommentsCell({
824
- rowId,
825
- columnId:
826
- ROW_INDEX_COLUMN_ID,
827
- });
828
- }}
829
- style={{
830
- top: '5px',
831
- right: '5px',
832
- }}
833
- className="absolute p-0.5 hover:bg-gray-100 rounded z-10"
834
- title={`${getCellUnresolvedCommentCount(rowId, ROW_INDEX_COLUMN_ID)} unresolved comment(s)`}
835
- >
836
- <FaComment
837
- className={cn(
838
- 'h-2.5 w-2.5',
839
- getCellUnresolvedCommentCount(
840
- rowId,
841
- ROW_INDEX_COLUMN_ID
842
- ) > 0
843
- ? 'text-amber-500'
844
- : 'text-gray-400'
845
- )}
846
- />
847
- {getCellUnresolvedCommentCount(
848
- rowId,
849
- ROW_INDEX_COLUMN_ID
850
- ) > 0 && (
851
- <span className="absolute -top-1 -right-1 bg-amber-500 text-white text-[6px] rounded-full w-2.5 h-2.5 flex items-center justify-center">
852
- {getCellUnresolvedCommentCount(
853
- rowId,
854
- ROW_INDEX_COLUMN_ID
855
- )}
856
- </span>
857
- )}
858
- </button>
859
- )}
860
-
861
- {/* Row Actions (visible on hover) */}
862
- <div className="absolute inset-x-0 bottom-0 opacity-0 group-hover:opacity-100 flex items-center justify-center gap-0.5 transition-opacity bg-white/90 py-0.5 border-t border-gray-100">
863
- {/* Clone/Duplicate Row */}
812
+ {/* Action buttons - absolute positioned to not affect centering */}
813
+ <div className="absolute right-0 flex items-center gap-0.5">
814
+ {/* Clone/Duplicate Row - hover only */}
864
815
  {onRowClone && (
865
816
  <button
866
817
  type="button"
@@ -868,14 +819,14 @@ export function Spreadsheet<T extends Record<string, any>>({
868
819
  e.stopPropagation();
869
820
  handleRowClone(row, rowId);
870
821
  }}
871
- className="p-0.5 hover:bg-gray-200 rounded"
822
+ className="opacity-0 group-hover:opacity-100 transition-opacity p-0.5 bg-gray-100 hover:bg-gray-200 rounded"
872
823
  title="Duplicate row"
873
824
  >
874
825
  <HiDuplicate className="h-2.5 w-2.5 text-gray-500" />
875
826
  </button>
876
827
  )}
877
828
 
878
- {/* Highlight Row */}
829
+ {/* Highlight Row - hover only */}
879
830
  {enableHighlighting && (
880
831
  <button
881
832
  type="button"
@@ -885,7 +836,7 @@ export function Spreadsheet<T extends Record<string, any>>({
885
836
  rowId
886
837
  );
887
838
  }}
888
- className="p-0.5 hover:bg-gray-200 rounded"
839
+ className="opacity-0 group-hover:opacity-100 transition-opacity p-0.5 bg-gray-100 hover:bg-gray-200 rounded"
889
840
  title="Highlight row"
890
841
  >
891
842
  <AiFillHighlight
@@ -899,26 +850,62 @@ export function Spreadsheet<T extends Record<string, any>>({
899
850
  </button>
900
851
  )}
901
852
 
902
- {/* Add Comment to Row Index */}
903
- {enableComments && (
904
- <button
905
- type="button"
906
- onClick={(e) => {
907
- e.stopPropagation();
908
- setCommentModalCell({
853
+ {/* Comment button - always visible when has comments, hover only when adding */}
854
+ {enableComments &&
855
+ (cellHasComments(
856
+ rowId,
857
+ ROW_INDEX_COLUMN_ID
858
+ ) ? (
859
+ <button
860
+ type="button"
861
+ onClick={(e) => {
862
+ e.stopPropagation();
863
+ setViewCommentsCell({
864
+ rowId,
865
+ columnId:
866
+ ROW_INDEX_COLUMN_ID,
867
+ });
868
+ }}
869
+ className="p-0.5 bg-amber-100 hover:bg-amber-200 rounded transition-colors flex items-center gap-0.5"
870
+ title={`${getCellUnresolvedCommentCount(rowId, ROW_INDEX_COLUMN_ID)} comment(s) - click to view`}
871
+ >
872
+ <FaComment className="h-2.5 w-2.5 text-amber-500" />
873
+ {getCellUnresolvedCommentCount(
909
874
  rowId,
910
- columnId:
911
- ROW_INDEX_COLUMN_ID,
912
- });
913
- }}
914
- className="p-0.5 hover:bg-gray-200 rounded"
915
- title="Add comment"
916
- >
917
- <FaRegComment className="h-2.5 w-2.5 text-gray-500" />
918
- </button>
919
- )}
875
+ ROW_INDEX_COLUMN_ID
876
+ ) > 0 && (
877
+ <span className="text-[9px] font-medium text-amber-600">
878
+ {getCellUnresolvedCommentCount(
879
+ rowId,
880
+ ROW_INDEX_COLUMN_ID
881
+ ) > 99
882
+ ? '99+'
883
+ : getCellUnresolvedCommentCount(
884
+ rowId,
885
+ ROW_INDEX_COLUMN_ID
886
+ )}
887
+ </span>
888
+ )}
889
+ </button>
890
+ ) : (
891
+ <button
892
+ type="button"
893
+ onClick={(e) => {
894
+ e.stopPropagation();
895
+ setCommentModalCell({
896
+ rowId,
897
+ columnId:
898
+ ROW_INDEX_COLUMN_ID,
899
+ });
900
+ }}
901
+ className="opacity-0 group-hover:opacity-100 transition-opacity p-0.5 bg-gray-100 hover:bg-gray-200 rounded"
902
+ title="Add comment"
903
+ >
904
+ <FaRegComment className="h-2.5 w-2.5 text-gray-500" />
905
+ </button>
906
+ ))}
920
907
 
921
- {/* Custom Row Actions */}
908
+ {/* Custom Row Actions - hover only */}
922
909
  {rowActions?.map((action) => {
923
910
  if (
924
911
  action.visible &&
@@ -937,7 +924,7 @@ export function Spreadsheet<T extends Record<string, any>>({
937
924
  );
938
925
  }}
939
926
  className={cn(
940
- 'p-0.5 hover:bg-gray-200 rounded',
927
+ 'opacity-0 group-hover:opacity-100 transition-opacity p-0.5 hover:bg-gray-200 rounded',
941
928
  action.className
942
929
  )}
943
930
  title={action.tooltip}
@@ -1102,6 +1089,16 @@ export function Spreadsheet<T extends Record<string, any>>({
1102
1089
  : undefined
1103
1090
  }
1104
1091
  onToggleResolved={handleToggleCommentResolved}
1092
+ onAddComment={
1093
+ viewCommentsCell !== null
1094
+ ? () => {
1095
+ // Close view modal and open add modal for the same cell
1096
+ const cell = viewCommentsCell;
1097
+ setViewCommentsCell(null);
1098
+ setCommentModalCell(cell);
1099
+ }
1100
+ : undefined
1101
+ }
1105
1102
  onClose={() => setViewCommentsCell(null)}
1106
1103
  />
1107
1104
 
@@ -234,34 +234,9 @@ export const SpreadsheetCell: React.FC<SpreadsheetCellProps> = ({
234
234
  {renderContent()}
235
235
  </div>
236
236
 
237
- {/* Comment indicator - absolutely positioned in top-right corner */}
238
- {hasComments && (
239
- <button
240
- type="button"
241
- onClick={(e) => {
242
- e.stopPropagation();
243
- onViewComments?.();
244
- }}
245
- className="absolute -right-1 p-0.5 hover:bg-gray-100 rounded z-10"
246
- title={`${unresolvedCommentCount} unresolved comment(s)`}
247
- >
248
- <FaComment
249
- className={cn(
250
- 'h-2.5 w-2.5',
251
- unresolvedCommentCount > 0 ? 'text-amber-500' : 'text-gray-400'
252
- )}
253
- />
254
- {unresolvedCommentCount > 0 && (
255
- <span className="absolute -top-1 -right-1 bg-amber-500 text-white text-[6px] rounded-full w-2.5 h-2.5 flex items-center justify-center">
256
- {unresolvedCommentCount}
257
- </span>
258
- )}
259
- </button>
260
- )}
261
-
262
- {/* Action buttons - show on hover */}
263
- <div className="opacity-0 group-hover:opacity-100 flex items-center gap-0.5 transition-opacity shrink-0">
264
- {/* Copy down button */}
237
+ {/* Action buttons - show on hover, except comment indicator which is always visible */}
238
+ <div className="flex items-center gap-0.5 shrink-0">
239
+ {/* Copy down button - hover only */}
265
240
  {value !== null && value !== undefined && value !== '' && onCopyDown && (
266
241
  <button
267
242
  type="button"
@@ -269,14 +244,14 @@ export const SpreadsheetCell: React.FC<SpreadsheetCellProps> = ({
269
244
  e.stopPropagation();
270
245
  onCopyDown();
271
246
  }}
272
- className="p-0.5 bg-gray-100 hover:bg-gray-200 rounded"
247
+ className="opacity-0 group-hover:opacity-100 transition-opacity p-0.5 bg-gray-100 hover:bg-gray-200 rounded"
273
248
  title="Copy value down to rows below"
274
249
  >
275
250
  <HiOutlineClipboardCopy className="h-2.5 w-2.5 text-gray-500" />
276
251
  </button>
277
252
  )}
278
253
 
279
- {/* Copy to selected button */}
254
+ {/* Copy to selected button - hover only */}
280
255
  {hasSelectedRows &&
281
256
  value !== null &&
282
257
  value !== undefined &&
@@ -288,14 +263,14 @@ export const SpreadsheetCell: React.FC<SpreadsheetCellProps> = ({
288
263
  e.stopPropagation();
289
264
  onCopyToSelected();
290
265
  }}
291
- className="p-0.5 bg-green-100 hover:bg-green-200 rounded"
266
+ className="opacity-0 group-hover:opacity-100 transition-opacity p-0.5 bg-green-100 hover:bg-green-200 rounded"
292
267
  title="Copy to selected rows"
293
268
  >
294
269
  <HiOutlineClipboardCheck className="h-2.5 w-2.5 text-green-600" />
295
270
  </button>
296
271
  )}
297
272
 
298
- {/* Highlight button */}
273
+ {/* Highlight button - hover only */}
299
274
  {onHighlight && (
300
275
  <button
301
276
  type="button"
@@ -303,32 +278,51 @@ export const SpreadsheetCell: React.FC<SpreadsheetCellProps> = ({
303
278
  e.stopPropagation();
304
279
  onHighlight();
305
280
  }}
306
- className="p-0.5 hover:bg-gray-100 rounded"
281
+ className="opacity-0 group-hover:opacity-100 transition-opacity p-0.5 bg-gray-100 hover:bg-gray-200 rounded"
307
282
  title="Highlight cell"
308
283
  >
309
284
  <AiFillHighlight
310
285
  className={cn(
311
286
  'h-2.5 w-2.5',
312
- highlightColor ? 'text-amber-500' : 'text-gray-400'
287
+ highlightColor ? 'text-amber-500' : 'text-gray-500'
313
288
  )}
314
289
  />
315
290
  </button>
316
291
  )}
317
292
 
318
- {/* Add comment button */}
319
- {onAddComment && (
293
+ {/* Comment button - always visible when has comments, hover only when adding */}
294
+ {hasComments && onViewComments ? (
295
+ <button
296
+ type="button"
297
+ onClick={(e) => {
298
+ e.stopPropagation();
299
+ onViewComments();
300
+ }}
301
+ className="p-0.5 bg-amber-100 hover:bg-amber-200 rounded transition-colors flex items-center gap-0.5"
302
+ title={`${unresolvedCommentCount} comment(s) - click to view`}
303
+ >
304
+ <FaComment className="h-2.5 w-2.5 text-amber-500" />
305
+ {unresolvedCommentCount > 0 && (
306
+ <span className="text-[9px] font-medium text-amber-600">
307
+ {unresolvedCommentCount > 99
308
+ ? '99+'
309
+ : unresolvedCommentCount}
310
+ </span>
311
+ )}
312
+ </button>
313
+ ) : onAddComment ? (
320
314
  <button
321
315
  type="button"
322
316
  onClick={(e) => {
323
317
  e.stopPropagation();
324
318
  onAddComment();
325
319
  }}
326
- className="p-0.5 hover:bg-gray-100 rounded"
320
+ className="opacity-0 group-hover:opacity-100 transition-opacity p-0.5 bg-gray-100 hover:bg-gray-200 rounded"
327
321
  title="Add comment"
328
322
  >
329
- <FaRegComment className="h-2.5 w-2.5 text-gray-400" />
323
+ <FaRegComment className="h-2.5 w-2.5 text-gray-500" />
330
324
  </button>
331
- )}
325
+ ) : null}
332
326
  </div>
333
327
  </div>
334
328
  )}
@@ -1,22 +0,0 @@
1
-
2
- > @xcelsior/ui-spreadsheets@1.0.4 build /home/circleci/repo/packages/ui/ui-spreadsheets
3
- > tsup && tsc --noEmit
4
-
5
- CLI Building entry: src/index.ts
6
- CLI Using tsconfig: tsconfig.json
7
- CLI tsup v8.5.1
8
- CLI Using tsup config: /home/circleci/repo/packages/ui/ui-spreadsheets/tsup.config.ts
9
- CLI Target: es2020
10
- CLI Cleaning output folder
11
- CJS Build start
12
- ESM Build start
13
- CJS dist/index.js 154.78 KB
14
- CJS dist/index.js.map 4.61 MB
15
- CJS ⚡️ Build success in 477ms
16
- ESM dist/index.mjs 143.85 KB
17
- ESM dist/index.mjs.map 4.61 MB
18
- ESM ⚡️ Build success in 479ms
19
- DTS Build start
20
- DTS ⚡️ Build success in 4317ms
21
- DTS dist/index.d.ts 22.21 KB
22
- DTS dist/index.d.mts 22.21 KB