@xcelsior/ui-spreadsheets 1.0.1

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.
Files changed (37) hide show
  1. package/.storybook/main.ts +27 -0
  2. package/.storybook/preview.tsx +28 -0
  3. package/.turbo/turbo-build.log +22 -0
  4. package/CHANGELOG.md +9 -0
  5. package/biome.json +3 -0
  6. package/dist/index.d.mts +687 -0
  7. package/dist/index.d.ts +687 -0
  8. package/dist/index.js +3459 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/index.mjs +3417 -0
  11. package/dist/index.mjs.map +1 -0
  12. package/package.json +51 -0
  13. package/postcss.config.js +5 -0
  14. package/src/components/ColorPickerPopover.tsx +73 -0
  15. package/src/components/ColumnHeaderActions.tsx +139 -0
  16. package/src/components/CommentModals.tsx +137 -0
  17. package/src/components/KeyboardShortcutsModal.tsx +119 -0
  18. package/src/components/RowIndexColumnHeader.tsx +70 -0
  19. package/src/components/Spreadsheet.stories.tsx +1146 -0
  20. package/src/components/Spreadsheet.tsx +1005 -0
  21. package/src/components/SpreadsheetCell.tsx +341 -0
  22. package/src/components/SpreadsheetFilterDropdown.tsx +341 -0
  23. package/src/components/SpreadsheetHeader.tsx +111 -0
  24. package/src/components/SpreadsheetSettingsModal.tsx +555 -0
  25. package/src/components/SpreadsheetToolbar.tsx +346 -0
  26. package/src/hooks/index.ts +40 -0
  27. package/src/hooks/useSpreadsheetComments.ts +132 -0
  28. package/src/hooks/useSpreadsheetFiltering.ts +379 -0
  29. package/src/hooks/useSpreadsheetHighlighting.ts +201 -0
  30. package/src/hooks/useSpreadsheetKeyboardShortcuts.ts +149 -0
  31. package/src/hooks/useSpreadsheetPinning.ts +203 -0
  32. package/src/hooks/useSpreadsheetUndoRedo.ts +167 -0
  33. package/src/index.ts +31 -0
  34. package/src/types.ts +612 -0
  35. package/src/utils.ts +16 -0
  36. package/tsconfig.json +30 -0
  37. package/tsup.config.ts +12 -0
package/src/types.ts ADDED
@@ -0,0 +1,612 @@
1
+ import type React from 'react';
2
+
3
+ /**
4
+ * Column definition for the spreadsheet
5
+ */
6
+ export interface SpreadsheetColumn<T = any> {
7
+ /** Unique identifier for the column */
8
+ id: string;
9
+ /** Display label for the column header */
10
+ label: string;
11
+ /** Width of the column in pixels */
12
+ width?: number;
13
+ /** Minimum width of the column in pixels */
14
+ minWidth?: number;
15
+ /** Text alignment */
16
+ align?: 'left' | 'center' | 'right';
17
+ /** Whether the column is sortable */
18
+ sortable?: boolean;
19
+ /** Whether the column is filterable */
20
+ filterable?: boolean;
21
+ /** Whether the column is editable */
22
+ editable?: boolean;
23
+ /** Whether the column can be pinned */
24
+ pinnable?: boolean;
25
+ /** Type of data in the column (for filtering/formatting) */
26
+ type?: 'text' | 'number' | 'date' | 'select' | 'boolean';
27
+ /** Options for select type columns */
28
+ options?: string[];
29
+ /** Custom render function for cell content */
30
+ render?: (value: any, row: T, rowIndex: number) => React.ReactNode;
31
+ /** Custom cell value getter */
32
+ getValue?: (row: T) => any;
33
+ /** Group this column belongs to */
34
+ group?: string;
35
+ /** Whether this column is frozen/sticky */
36
+ frozen?: boolean;
37
+ }
38
+
39
+ /**
40
+ * Column group definition
41
+ */
42
+ export interface SpreadsheetColumnGroup {
43
+ /** Unique identifier for the group */
44
+ id: string;
45
+ /** Display label for the group header */
46
+ label: string;
47
+ /** Column IDs in this group */
48
+ columns: string[];
49
+ /** Whether the group is collapsible */
50
+ collapsible?: boolean;
51
+ /** Background color for the group header */
52
+ headerColor?: string;
53
+ }
54
+
55
+ /**
56
+ * Sort configuration
57
+ */
58
+ export interface SpreadsheetSortConfig {
59
+ /** Column ID to sort by */
60
+ columnId: string;
61
+ /** Sort direction */
62
+ direction: 'asc' | 'desc';
63
+ }
64
+
65
+ /**
66
+ * Text filter operator types for Excel-like filtering
67
+ */
68
+ export type TextFilterOperator =
69
+ | 'contains'
70
+ | 'notContains'
71
+ | 'equals'
72
+ | 'notEquals'
73
+ | 'startsWith'
74
+ | 'endsWith'
75
+ | 'isEmpty'
76
+ | 'isNotEmpty';
77
+
78
+ /**
79
+ * Number filter operator types for Excel-like filtering
80
+ */
81
+ export type NumberFilterOperator =
82
+ | 'equals'
83
+ | 'notEquals'
84
+ | 'greaterThan'
85
+ | 'greaterThanOrEqual'
86
+ | 'lessThan'
87
+ | 'lessThanOrEqual'
88
+ | 'between'
89
+ | 'isEmpty'
90
+ | 'isNotEmpty';
91
+
92
+ /**
93
+ * Date filter operator types for Excel-like filtering
94
+ */
95
+ export type DateFilterOperator =
96
+ | 'equals'
97
+ | 'notEquals'
98
+ | 'before'
99
+ | 'after'
100
+ | 'between'
101
+ | 'today'
102
+ | 'yesterday'
103
+ | 'thisWeek'
104
+ | 'lastWeek'
105
+ | 'thisMonth'
106
+ | 'lastMonth'
107
+ | 'thisYear'
108
+ | 'isEmpty'
109
+ | 'isNotEmpty';
110
+
111
+ /**
112
+ * Text filter condition
113
+ */
114
+ export interface TextFilterCondition {
115
+ operator: TextFilterOperator;
116
+ value?: string;
117
+ }
118
+
119
+ /**
120
+ * Number filter condition
121
+ */
122
+ export interface NumberFilterCondition {
123
+ operator: NumberFilterOperator;
124
+ value?: number;
125
+ valueTo?: number; // For 'between' operator
126
+ }
127
+
128
+ /**
129
+ * Date filter condition
130
+ */
131
+ export interface DateFilterCondition {
132
+ operator: DateFilterOperator;
133
+ value?: string; // ISO date string
134
+ valueTo?: string; // For 'between' operator
135
+ }
136
+
137
+ /**
138
+ * Filter configuration for a single column
139
+ */
140
+ export interface SpreadsheetColumnFilter {
141
+ /** Text search filter (legacy, still supported) */
142
+ text?: string;
143
+ /** Minimum value for range filtering (legacy, still supported) */
144
+ min?: string | number;
145
+ /** Maximum value for range filtering (legacy, still supported) */
146
+ max?: string | number;
147
+ /** Selected values for multi-select filtering */
148
+ selectedValues?: string[];
149
+ /** Text filter condition for advanced filtering */
150
+ textCondition?: TextFilterCondition;
151
+ /** Number filter condition for advanced filtering */
152
+ numberCondition?: NumberFilterCondition;
153
+ /** Date filter condition for advanced filtering */
154
+ dateCondition?: DateFilterCondition;
155
+ /** Include blank/empty values */
156
+ includeBlanks?: boolean;
157
+ /** Exclude blank/empty values */
158
+ excludeBlanks?: boolean;
159
+ }
160
+
161
+ /**
162
+ * Cell position identifier
163
+ */
164
+ export interface CellPosition {
165
+ /** Row ID or index */
166
+ rowId: string | number;
167
+ /** Column ID */
168
+ columnId: string;
169
+ }
170
+
171
+ /**
172
+ * Cell highlight configuration
173
+ */
174
+ export interface CellHighlight {
175
+ /** Row ID (optional for column highlights) */
176
+ rowId?: string | number;
177
+ /** Column ID (optional for row highlights) */
178
+ columnId?: string;
179
+ /** Highlight color */
180
+ color: string;
181
+ }
182
+
183
+ /**
184
+ * Cell comment
185
+ */
186
+ export interface CellComment {
187
+ /** Unique ID */
188
+ id: string;
189
+ /** Row ID */
190
+ rowId: string | number;
191
+ /** Column ID (optional for row comments) */
192
+ columnId?: string;
193
+ /** Comment text */
194
+ text: string;
195
+ /** Author name */
196
+ author?: string;
197
+ /** Timestamp */
198
+ timestamp: Date;
199
+ /** Whether the comment is resolved */
200
+ resolved?: boolean;
201
+ }
202
+
203
+ /**
204
+ * Selection state
205
+ */
206
+ export interface SelectionState {
207
+ /** Selected row IDs */
208
+ selectedRows: Set<string | number>;
209
+ /** Focused cell position */
210
+ focusedCell: CellPosition | null;
211
+ /** Last selected row (for shift-click range selection) */
212
+ lastSelectedRow: string | number | null;
213
+ }
214
+
215
+ /**
216
+ * Pagination state
217
+ */
218
+ export interface PaginationState {
219
+ /** Current page (1-indexed) */
220
+ currentPage: number;
221
+ /** Number of rows per page */
222
+ pageSize: number;
223
+ /** Total number of rows */
224
+ totalRows: number;
225
+ }
226
+
227
+ /**
228
+ * Spreadsheet state
229
+ */
230
+ export interface SpreadsheetState<T = any> {
231
+ /** All data rows */
232
+ data: T[];
233
+ /** Column definitions */
234
+ columns: SpreadsheetColumn<T>[];
235
+ /** Column groups */
236
+ columnGroups?: SpreadsheetColumnGroup[];
237
+ /** Current sort configuration */
238
+ sortConfig: SpreadsheetSortConfig | null;
239
+ /** Column filters */
240
+ filters: Record<string, SpreadsheetColumnFilter>;
241
+ /** Selection state */
242
+ selection: SelectionState;
243
+ /** Pagination state */
244
+ pagination: PaginationState;
245
+ /** Collapsed column groups */
246
+ collapsedGroups: Set<string>;
247
+ /** Pinned columns */
248
+ pinnedColumns: Map<string, 'left' | 'right'>;
249
+ /** Cell highlights */
250
+ highlights: CellHighlight[];
251
+ /** Cell comments */
252
+ comments: CellComment[];
253
+ /** Zoom level (percentage) */
254
+ zoom: number;
255
+ /** Whether there are unsaved changes */
256
+ hasUnsavedChanges: boolean;
257
+ }
258
+
259
+ /**
260
+ * Row action configuration
261
+ */
262
+ export interface RowAction<T = any> {
263
+ /** Unique identifier */
264
+ id: string;
265
+ /** Icon component */
266
+ icon: React.ReactNode;
267
+ /** Tooltip text */
268
+ tooltip: string;
269
+ /** Callback when action is clicked */
270
+ onClick: (row: T, rowId: string | number) => void;
271
+ /** Whether the action is visible */
272
+ visible?: (row: T) => boolean;
273
+ /** Custom className */
274
+ className?: string;
275
+ }
276
+
277
+ /**
278
+ * Server-side pagination state for controlled pagination
279
+ */
280
+ export interface ServerSidePaginationState {
281
+ /** Current page (1-indexed) */
282
+ currentPage: number;
283
+ /** Number of rows per page */
284
+ pageSize: number;
285
+ /** Total number of items (required for server-side pagination) */
286
+ totalItems: number;
287
+ }
288
+
289
+ /**
290
+ * Props for the main Spreadsheet component
291
+ */
292
+ export interface SpreadsheetProps<T = any> {
293
+ /** Data rows */
294
+ data: T[];
295
+ /** Column definitions */
296
+ columns: SpreadsheetColumn<T>[];
297
+ /** Column groups */
298
+ columnGroups?: SpreadsheetColumnGroup[];
299
+ /** Unique key accessor for each row */
300
+ getRowId: (row: T) => string | number;
301
+ /** Callback when a cell value is edited */
302
+ onCellEdit?: (rowId: string | number, columnId: string, newValue: any) => void;
303
+ /** Callback when selection changes */
304
+ onSelectionChange?: (selectedRows: (string | number)[]) => void;
305
+ /** Callback when sort changes */
306
+ onSortChange?: (sortConfig: SpreadsheetSortConfig | null) => void;
307
+ /** Callback when filters change */
308
+ onFilterChange?: (filters: Record<string, SpreadsheetColumnFilter>) => void;
309
+ /** Callback for row click */
310
+ onRowClick?: (row: T, rowIndex: number) => void;
311
+ /** Callback for row double click */
312
+ onRowDoubleClick?: (row: T, rowIndex: number) => void;
313
+ /** Callback when a row is cloned/duplicated */
314
+ onRowClone?: (row: T, rowId: string | number) => void;
315
+ /** Callback when a row comment is added */
316
+ onAddRowComment?: (rowId: string | number, comment: string) => void;
317
+ /** Callback when row highlight is toggled */
318
+ onRowHighlight?: (rowId: string | number, color: string | null) => void;
319
+ /** Whether to show the toolbar */
320
+ showToolbar?: boolean;
321
+ /** Whether to show pagination */
322
+ showPagination?: boolean;
323
+ /** Whether to show row index column (#) */
324
+ showRowIndex?: boolean;
325
+ /** Whether to enable row selection */
326
+ enableRowSelection?: boolean;
327
+ /** Whether to enable cell editing */
328
+ enableCellEditing?: boolean;
329
+ /** Whether to enable cell comments */
330
+ enableComments?: boolean;
331
+ /** Whether to enable cell highlighting */
332
+ enableHighlighting?: boolean;
333
+ /** Whether to enable undo/redo */
334
+ enableUndoRedo?: boolean;
335
+ /** Initial page size */
336
+ defaultPageSize?: number;
337
+ /** Available page size options */
338
+ pageSizeOptions?: number[];
339
+ /** Initial zoom level */
340
+ defaultZoom?: number;
341
+ /** Whether to auto-save changes */
342
+ autoSave?: boolean;
343
+ /** Whether to use compact mode (smaller cells) */
344
+ compactMode?: boolean;
345
+ /** Loading state */
346
+ isLoading?: boolean;
347
+ /** Custom className */
348
+ className?: string;
349
+ /** Empty state message */
350
+ emptyMessage?: string;
351
+ /** Row highlights (externally controlled) */
352
+ rowHighlights?: CellHighlight[];
353
+ /** Row comments (externally controlled) */
354
+ rowComments?: CellComment[];
355
+ /** Custom row actions to display in the index column */
356
+ rowActions?: RowAction<T>[];
357
+
358
+ // ==================== SERVER-SIDE MODE ====================
359
+ /**
360
+ * Enable server-side mode for filtering, sorting, and pagination.
361
+ * When enabled, the component will NOT perform client-side filtering, sorting, or pagination.
362
+ * Instead, it expects the `data` prop to already be filtered, sorted, and paginated by the server.
363
+ * @default false
364
+ */
365
+ serverSide?: boolean;
366
+ /**
367
+ * Total number of items (required when serverSide is true).
368
+ * Used to calculate pagination correctly when data is paginated server-side.
369
+ */
370
+ totalItems?: number;
371
+ /**
372
+ * Controlled current page (1-indexed). Use with serverSide mode for controlled pagination.
373
+ * When provided, the component becomes controlled for pagination.
374
+ */
375
+ currentPage?: number;
376
+ /**
377
+ * Controlled page size. Use with serverSide mode for controlled pagination.
378
+ * When provided along with currentPage, pagination becomes fully controlled.
379
+ */
380
+ pageSize?: number;
381
+ /**
382
+ * Callback when page changes. Required for serverSide pagination to work.
383
+ * Called with (page: number, pageSize: number) when the user changes pages or page size.
384
+ */
385
+ onPageChange?: (page: number, pageSize: number) => void;
386
+ /**
387
+ * Controlled sort configuration. Use with serverSide mode for controlled sorting.
388
+ * When provided, sorting becomes controlled by the parent component.
389
+ */
390
+ sortConfig?: SpreadsheetSortConfig | null;
391
+ /**
392
+ * Controlled filters. Use with serverSide mode for controlled filtering.
393
+ * When provided, filtering becomes controlled by the parent component.
394
+ */
395
+ filters?: Record<string, SpreadsheetColumnFilter>;
396
+ }
397
+
398
+ /**
399
+ * Props for SpreadsheetCell component
400
+ */
401
+ export interface SpreadsheetCellProps {
402
+ /** Cell value */
403
+ value: any;
404
+ /** Column definition */
405
+ column: SpreadsheetColumn;
406
+ /** Row data */
407
+ row: any;
408
+ /** Row index */
409
+ rowIndex: number;
410
+ /** Row ID */
411
+ rowId: string | number;
412
+ /** Whether the cell is editable */
413
+ isEditable?: boolean;
414
+ /** Whether the cell is currently being edited */
415
+ isEditing?: boolean;
416
+ /** Whether the cell is focused */
417
+ isFocused?: boolean;
418
+ /** Whether the row is selected */
419
+ isRowSelected?: boolean;
420
+ /** Whether the row is hovered */
421
+ isRowHovered?: boolean;
422
+ /** Highlight color */
423
+ highlightColor?: string;
424
+ /** Whether the cell has comments */
425
+ hasComments?: boolean;
426
+ /** Number of unresolved comments */
427
+ unresolvedCommentCount?: number;
428
+ /** Whether the cell was recently copied */
429
+ isCopied?: boolean;
430
+ /** Compact mode */
431
+ compactMode?: boolean;
432
+ /** Whether the column is pinned */
433
+ isPinned?: boolean;
434
+ /** Pin side */
435
+ pinSide?: 'left' | 'right';
436
+ /** Left offset for sticky positioning */
437
+ leftOffset?: number;
438
+ /** Right offset for sticky positioning */
439
+ rightOffset?: number;
440
+ /** Callback when cell is clicked */
441
+ onClick?: (event: React.MouseEvent) => void;
442
+ /** Callback when cell value changes */
443
+ onChange?: (newValue: any) => void;
444
+ /** Callback when editing is confirmed */
445
+ onConfirm?: () => void;
446
+ /** Callback when editing is cancelled */
447
+ onCancel?: () => void;
448
+ /** Callback to copy value down */
449
+ onCopyDown?: () => void;
450
+ /** Callback to copy to selected rows */
451
+ onCopyToSelected?: () => void;
452
+ /** Callback to add highlight */
453
+ onHighlight?: () => void;
454
+ /** Callback to add comment */
455
+ onAddComment?: () => void;
456
+ /** Callback to view comments */
457
+ onViewComments?: () => void;
458
+ /** Whether there are selected rows (for showing copy to selected button) */
459
+ hasSelectedRows?: boolean;
460
+ /** Custom className */
461
+ className?: string;
462
+ }
463
+
464
+ /**
465
+ * Props for SpreadsheetHeader component
466
+ */
467
+ export interface SpreadsheetHeaderProps {
468
+ /** Column definition */
469
+ column: SpreadsheetColumn;
470
+ /** Current sort configuration */
471
+ sortConfig: SpreadsheetSortConfig | null;
472
+ /** Whether the column has active filters */
473
+ hasActiveFilter?: boolean;
474
+ /** Whether the column is pinned */
475
+ isPinned?: boolean;
476
+ /** Pin side */
477
+ pinSide?: 'left' | 'right';
478
+ /** Left offset for sticky positioning */
479
+ leftOffset?: number;
480
+ /** Right offset for sticky positioning */
481
+ rightOffset?: number;
482
+ /** Highlight color */
483
+ highlightColor?: string;
484
+ /** Compact mode */
485
+ compactMode?: boolean;
486
+ /** Callback when column header is clicked (sorting) */
487
+ onClick?: () => void;
488
+ /** Callback to toggle filter dropdown */
489
+ onFilterClick?: () => void;
490
+ /** Callback to toggle pin */
491
+ onPinClick?: () => void;
492
+ /** Callback to highlight column */
493
+ onHighlightClick?: () => void;
494
+ /** Custom className */
495
+ className?: string;
496
+ }
497
+
498
+ /**
499
+ * Props for SpreadsheetFilterDropdown component
500
+ */
501
+ export interface SpreadsheetFilterDropdownProps {
502
+ /** Column definition */
503
+ column: SpreadsheetColumn;
504
+ /** Current filter value */
505
+ filter?: SpreadsheetColumnFilter;
506
+ /** All unique values in the column (for select filter) - optional, not currently used */
507
+ uniqueValues?: string[];
508
+ /** Callback when filter changes */
509
+ onFilterChange: (filter: SpreadsheetColumnFilter | undefined) => void;
510
+ /** Callback to close dropdown */
511
+ onClose: () => void;
512
+ /** Custom className */
513
+ className?: string;
514
+ }
515
+
516
+ /**
517
+ * Props for SpreadsheetPagination component
518
+ */
519
+ export interface SpreadsheetPaginationProps {
520
+ /** Current page (1-indexed) */
521
+ currentPage: number;
522
+ /** Total number of pages */
523
+ totalPages: number;
524
+ /** Number of rows per page */
525
+ pageSize: number;
526
+ /** Total number of rows */
527
+ totalRows: number;
528
+ /** Start index of current page (1-indexed) */
529
+ startRow: number;
530
+ /** End index of current page */
531
+ endRow: number;
532
+ /** Available page size options */
533
+ pageSizeOptions?: number[];
534
+ /** Callback when page changes */
535
+ onPageChange: (page: number) => void;
536
+ /** Callback when page size changes */
537
+ onPageSizeChange: (pageSize: number) => void;
538
+ /** Custom className */
539
+ className?: string;
540
+ }
541
+
542
+ /**
543
+ * Props for SpreadsheetToolbar component
544
+ */
545
+ export interface SpreadsheetToolbarProps {
546
+ /** Current zoom level */
547
+ zoom: number;
548
+ /** Whether undo is available */
549
+ canUndo: boolean;
550
+ /** Whether redo is available */
551
+ canRedo: boolean;
552
+ /** Number of undo actions available */
553
+ undoCount?: number;
554
+ /** Number of redo actions available */
555
+ redoCount?: number;
556
+ /** Number of selected rows */
557
+ selectedRowCount: number;
558
+ /** Whether there are unsaved changes */
559
+ hasUnsavedChanges: boolean;
560
+ /** Save status */
561
+ saveStatus: 'saved' | 'saving' | 'unsaved' | 'error';
562
+ /** Whether auto-save is enabled */
563
+ autoSave: boolean;
564
+ /** Summary data to display */
565
+ summary?: {
566
+ label: string;
567
+ value: string | number;
568
+ variant?: 'success' | 'danger' | 'warning' | 'info';
569
+ };
570
+ /** Callback for zoom in */
571
+ onZoomIn: () => void;
572
+ /** Callback for zoom out */
573
+ onZoomOut: () => void;
574
+ /** Callback for zoom reset */
575
+ onZoomReset: () => void;
576
+ /** Callback for undo */
577
+ onUndo: () => void;
578
+ /** Callback for redo */
579
+ onRedo: () => void;
580
+ /** Callback for clear selection */
581
+ onClearSelection: () => void;
582
+ /** Callback for manual save */
583
+ onSave?: () => void;
584
+ /** Callback for export */
585
+ onExport?: () => void;
586
+ /** Callback for settings */
587
+ onSettings?: () => void;
588
+ /** Callback for keyboard shortcuts */
589
+ onShowShortcuts?: () => void;
590
+ /** Whether there are active filters */
591
+ hasActiveFilters?: boolean;
592
+ /** Callback to clear all filters */
593
+ onClearFilters?: () => void;
594
+ /** Custom className */
595
+ className?: string;
596
+ }
597
+
598
+ /**
599
+ * Props for SpreadsheetColumnGroupHeader component
600
+ */
601
+ export interface SpreadsheetColumnGroupHeaderProps {
602
+ /** Group definition */
603
+ group: SpreadsheetColumnGroup;
604
+ /** Number of visible columns in the group */
605
+ colSpan: number;
606
+ /** Whether the group is collapsed */
607
+ isCollapsed: boolean;
608
+ /** Callback to toggle collapse */
609
+ onToggleCollapse: () => void;
610
+ /** Custom className */
611
+ className?: string;
612
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,16 @@
1
+ // Helper function to check if value is blank/empty
2
+ import { type ClassValue, clsx } from 'clsx';
3
+ import { twMerge } from 'tailwind-merge';
4
+
5
+ export const isBlankValue = (value: any): boolean => {
6
+ return (
7
+ value === null ||
8
+ value === undefined ||
9
+ value === '' ||
10
+ (typeof value === 'string' && value.trim() === '')
11
+ );
12
+ };
13
+
14
+ export function cn(...inputs: ClassValue[]) {
15
+ return twMerge(clsx(inputs));
16
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "lib": ["DOM", "DOM.Iterable", "ESNext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "esModuleInterop": true,
8
+ "allowSyntheticDefaultImports": true,
9
+ "strict": true,
10
+ "noImplicitAny": false,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "module": "ESNext",
13
+ "moduleResolution": "bundler",
14
+ "resolveJsonModule": true,
15
+ "isolatedModules": true,
16
+ "noEmit": true,
17
+ "jsx": "react-jsx",
18
+ "declaration": true,
19
+ "outDir": "./dist",
20
+ "baseUrl": ".",
21
+ "paths": {
22
+ "@/*": ["./src/*"],
23
+ "@components/*": ["./src/components/*"],
24
+ "@utils/*": ["./src/utils/*"],
25
+ "@types/*": ["./src/types/*"]
26
+ }
27
+ },
28
+ "include": ["src"],
29
+ "exclude": ["node_modules", "dist"]
30
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from 'tsup';
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts'],
5
+ format: ['cjs', 'esm'],
6
+ dts: true,
7
+ splitting: false,
8
+ sourcemap: true,
9
+ clean: true,
10
+ external: ['react', 'react-dom', '@xcelsior/design-system'],
11
+ outDir: 'dist',
12
+ });