@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/.turbo/turbo-lint.log +61 -0
- package/dist/index.js +79 -86
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +79 -86
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/CommentModals.tsx +15 -0
- package/src/components/Spreadsheet.stories.tsx +1 -1
- package/src/components/Spreadsheet.tsx +74 -77
- package/src/components/SpreadsheetCell.tsx +33 -39
- package/.turbo/turbo-build.log +0 -22
package/package.json
CHANGED
|
@@ -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:
|
|
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=
|
|
809
|
-
{/* Row number */}
|
|
810
|
-
<
|
|
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
|
-
{/*
|
|
815
|
-
|
|
816
|
-
|
|
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
|
-
{/*
|
|
903
|
-
{enableComments &&
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
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
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
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
|
-
{/*
|
|
238
|
-
|
|
239
|
-
|
|
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-
|
|
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-
|
|
287
|
+
highlightColor ? 'text-amber-500' : 'text-gray-500'
|
|
313
288
|
)}
|
|
314
289
|
/>
|
|
315
290
|
</button>
|
|
316
291
|
)}
|
|
317
292
|
|
|
318
|
-
{/*
|
|
319
|
-
{
|
|
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-
|
|
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-
|
|
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
|
)}
|
package/.turbo/turbo-build.log
DELETED
|
@@ -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
|
-
[34mCLI[39m Building entry: src/index.ts
|
|
6
|
-
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
|
-
[34mCLI[39m tsup v8.5.1
|
|
8
|
-
[34mCLI[39m Using tsup config: /home/circleci/repo/packages/ui/ui-spreadsheets/tsup.config.ts
|
|
9
|
-
[34mCLI[39m Target: es2020
|
|
10
|
-
[34mCLI[39m Cleaning output folder
|
|
11
|
-
[34mCJS[39m Build start
|
|
12
|
-
[34mESM[39m Build start
|
|
13
|
-
[32mCJS[39m [1mdist/index.js [22m[32m154.78 KB[39m
|
|
14
|
-
[32mCJS[39m [1mdist/index.js.map [22m[32m4.61 MB[39m
|
|
15
|
-
[32mCJS[39m ⚡️ Build success in 477ms
|
|
16
|
-
[32mESM[39m [1mdist/index.mjs [22m[32m143.85 KB[39m
|
|
17
|
-
[32mESM[39m [1mdist/index.mjs.map [22m[32m4.61 MB[39m
|
|
18
|
-
[32mESM[39m ⚡️ Build success in 479ms
|
|
19
|
-
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in 4317ms
|
|
21
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m22.21 KB[39m
|
|
22
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[32m22.21 KB[39m
|