@papernote/ui 1.2.0 → 1.3.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.
- package/dist/components/Box.d.ts +2 -1
- package/dist/components/Box.d.ts.map +1 -1
- package/dist/components/Button.d.ts +10 -1
- package/dist/components/Button.d.ts.map +1 -1
- package/dist/components/Card.d.ts +11 -2
- package/dist/components/Card.d.ts.map +1 -1
- package/dist/components/DataTable.d.ts +17 -3
- package/dist/components/DataTable.d.ts.map +1 -1
- package/dist/components/EmptyState.d.ts +3 -1
- package/dist/components/EmptyState.d.ts.map +1 -1
- package/dist/components/Grid.d.ts +4 -2
- package/dist/components/Grid.d.ts.map +1 -1
- package/dist/components/Input.d.ts +2 -0
- package/dist/components/Input.d.ts.map +1 -1
- package/dist/components/MultiSelect.d.ts +13 -1
- package/dist/components/MultiSelect.d.ts.map +1 -1
- package/dist/components/Spreadsheet.d.ts +5 -1
- package/dist/components/Spreadsheet.d.ts.map +1 -1
- package/dist/components/Stack.d.ts +25 -5
- package/dist/components/Stack.d.ts.map +1 -1
- package/dist/components/Text.d.ts +20 -4
- package/dist/components/Text.d.ts.map +1 -1
- package/dist/components/Textarea.d.ts +2 -0
- package/dist/components/Textarea.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -3
- package/dist/components/index.d.ts.map +1 -1
- package/dist/index.d.ts +115 -49
- package/dist/index.esm.js +187 -8563
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +186 -8563
- package/dist/index.js.map +1 -1
- package/dist/styles.css +8 -51
- package/package.json +4 -4
- package/src/components/Box.stories.tsx +377 -0
- package/src/components/Box.tsx +8 -4
- package/src/components/Button.tsx +23 -10
- package/src/components/Card.tsx +20 -5
- package/src/components/DataTable.stories.tsx +36 -25
- package/src/components/DataTable.tsx +95 -5
- package/src/components/EmptyState.stories.tsx +124 -72
- package/src/components/EmptyState.tsx +10 -0
- package/src/components/Grid.stories.tsx +348 -0
- package/src/components/Grid.tsx +12 -5
- package/src/components/Input.tsx +12 -2
- package/src/components/MultiSelect.tsx +41 -10
- package/src/components/Spreadsheet.tsx +8 -57
- package/src/components/Stack.stories.tsx +24 -1
- package/src/components/Stack.tsx +40 -10
- package/src/components/Text.stories.tsx +273 -0
- package/src/components/Text.tsx +33 -8
- package/src/components/Textarea.tsx +32 -21
- package/src/components/index.ts +1 -4
- package/dist/components/Table.d.ts +0 -26
- package/dist/components/Table.d.ts.map +0 -1
- package/src/components/Table.tsx +0 -239
package/src/components/Table.tsx
DELETED
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import { ArrowUp, ArrowDown, ArrowUpDown, ChevronDown, ChevronRight } from 'lucide-react';
|
|
3
|
-
|
|
4
|
-
export type SortDirection = 'asc' | 'desc' | null;
|
|
5
|
-
|
|
6
|
-
export interface Column<T> {
|
|
7
|
-
key: string;
|
|
8
|
-
header: string;
|
|
9
|
-
accessor?: (row: T) => React.ReactNode;
|
|
10
|
-
sortable?: boolean;
|
|
11
|
-
filterable?: boolean;
|
|
12
|
-
width?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface TableProps<T> {
|
|
16
|
-
data: T[];
|
|
17
|
-
columns: Column<T>[];
|
|
18
|
-
keyExtractor: (row: T) => string;
|
|
19
|
-
selectable?: boolean;
|
|
20
|
-
expandable?: boolean;
|
|
21
|
-
onRowSelect?: (selectedRows: string[]) => void;
|
|
22
|
-
renderExpandedRow?: (row: T) => React.ReactNode;
|
|
23
|
-
emptyState?: React.ReactNode;
|
|
24
|
-
className?: string;
|
|
25
|
-
onSort?: (columnKey: string, direction: SortDirection) => void;
|
|
26
|
-
sortColumn?: string | null;
|
|
27
|
-
sortDirection?: SortDirection;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export default function Table<T>({
|
|
31
|
-
data,
|
|
32
|
-
columns,
|
|
33
|
-
keyExtractor,
|
|
34
|
-
selectable = false,
|
|
35
|
-
expandable = false,
|
|
36
|
-
onRowSelect,
|
|
37
|
-
renderExpandedRow,
|
|
38
|
-
emptyState,
|
|
39
|
-
className = '',
|
|
40
|
-
onSort,
|
|
41
|
-
sortColumn: externalSortColumn,
|
|
42
|
-
sortDirection: externalSortDirection,
|
|
43
|
-
}: TableProps<T>) {
|
|
44
|
-
const [internalSortColumn, setInternalSortColumn] = useState<string | null>(null);
|
|
45
|
-
const [internalSortDirection, setInternalSortDirection] = useState<SortDirection>(null);
|
|
46
|
-
|
|
47
|
-
// Use external sort state if provided, otherwise use internal state
|
|
48
|
-
const sortColumn = externalSortColumn !== undefined ? externalSortColumn : internalSortColumn;
|
|
49
|
-
const sortDirection = externalSortDirection !== undefined ? externalSortDirection : internalSortDirection;
|
|
50
|
-
const [selectedRows, setSelectedRows] = useState<Set<string>>(new Set());
|
|
51
|
-
const [expandedRows, setExpandedRows] = useState<Set<string>>(new Set());
|
|
52
|
-
|
|
53
|
-
// Handle sorting
|
|
54
|
-
const handleSort = (columnKey: string) => {
|
|
55
|
-
let newDirection: SortDirection;
|
|
56
|
-
|
|
57
|
-
if (sortColumn === columnKey) {
|
|
58
|
-
if (sortDirection === 'asc') {
|
|
59
|
-
newDirection = 'desc';
|
|
60
|
-
} else if (sortDirection === 'desc') {
|
|
61
|
-
newDirection = null;
|
|
62
|
-
} else {
|
|
63
|
-
newDirection = 'asc';
|
|
64
|
-
}
|
|
65
|
-
} else {
|
|
66
|
-
newDirection = 'asc';
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// If using external sort control, call the callback
|
|
70
|
-
if (onSort) {
|
|
71
|
-
onSort(columnKey, newDirection);
|
|
72
|
-
} else {
|
|
73
|
-
// Otherwise update internal state
|
|
74
|
-
setInternalSortColumn(newDirection === null ? null : columnKey);
|
|
75
|
-
setInternalSortDirection(newDirection);
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
// Handle row selection
|
|
80
|
-
const handleRowSelect = (rowKey: string) => {
|
|
81
|
-
const newSelected = new Set(selectedRows);
|
|
82
|
-
if (newSelected.has(rowKey)) {
|
|
83
|
-
newSelected.delete(rowKey);
|
|
84
|
-
} else {
|
|
85
|
-
newSelected.add(rowKey);
|
|
86
|
-
}
|
|
87
|
-
setSelectedRows(newSelected);
|
|
88
|
-
onRowSelect?.(Array.from(newSelected));
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
// Handle select all
|
|
92
|
-
const handleSelectAll = () => {
|
|
93
|
-
if (selectedRows.size === data.length) {
|
|
94
|
-
setSelectedRows(new Set());
|
|
95
|
-
onRowSelect?.([]);
|
|
96
|
-
} else {
|
|
97
|
-
const allKeys = new Set(data.map(keyExtractor));
|
|
98
|
-
setSelectedRows(allKeys);
|
|
99
|
-
onRowSelect?.(Array.from(allKeys));
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
// Handle row expansion
|
|
104
|
-
const handleRowExpand = (rowKey: string) => {
|
|
105
|
-
const newExpanded = new Set(expandedRows);
|
|
106
|
-
if (newExpanded.has(rowKey)) {
|
|
107
|
-
newExpanded.delete(rowKey);
|
|
108
|
-
} else {
|
|
109
|
-
newExpanded.add(rowKey);
|
|
110
|
-
}
|
|
111
|
-
setExpandedRows(newExpanded);
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
const getSortIcon = (columnKey: string) => {
|
|
115
|
-
if (sortColumn !== columnKey) {
|
|
116
|
-
return <ArrowUpDown className="h-4 w-4 text-ink-400" />;
|
|
117
|
-
}
|
|
118
|
-
if (sortDirection === 'asc') {
|
|
119
|
-
return <ArrowUp className="h-4 w-4 text-accent-600" />;
|
|
120
|
-
}
|
|
121
|
-
if (sortDirection === 'desc') {
|
|
122
|
-
return <ArrowDown className="h-4 w-4 text-accent-600" />;
|
|
123
|
-
}
|
|
124
|
-
return <ArrowUpDown className="h-4 w-4 text-ink-400" />;
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
if (data.length === 0 && emptyState) {
|
|
128
|
-
return <div>{emptyState}</div>;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return (
|
|
132
|
-
<div className={`overflow-x-auto ${className}`}>
|
|
133
|
-
<table className="table">
|
|
134
|
-
<thead className="table-header">
|
|
135
|
-
<tr>
|
|
136
|
-
{/* Select All Checkbox */}
|
|
137
|
-
{selectable && (
|
|
138
|
-
<th className="table-header-cell w-12">
|
|
139
|
-
<input
|
|
140
|
-
type="checkbox"
|
|
141
|
-
checked={selectedRows.size === data.length && data.length > 0}
|
|
142
|
-
onChange={handleSelectAll}
|
|
143
|
-
className="w-4 h-4 text-accent-600 border-paper-300 rounded focus:ring-accent-400"
|
|
144
|
-
aria-label="Select all rows"
|
|
145
|
-
/>
|
|
146
|
-
</th>
|
|
147
|
-
)}
|
|
148
|
-
|
|
149
|
-
{/* Expand Column */}
|
|
150
|
-
{expandable && <th className="table-header-cell w-12"></th>}
|
|
151
|
-
|
|
152
|
-
{/* Data Columns */}
|
|
153
|
-
{columns.map((column) => (
|
|
154
|
-
<th
|
|
155
|
-
key={column.key}
|
|
156
|
-
className="table-header-cell"
|
|
157
|
-
style={{ width: column.width }}
|
|
158
|
-
>
|
|
159
|
-
{column.sortable ? (
|
|
160
|
-
<button
|
|
161
|
-
onClick={() => handleSort(column.key)}
|
|
162
|
-
className="group inline-flex items-center gap-2 hover:text-ink-900 transition-colors"
|
|
163
|
-
>
|
|
164
|
-
<span>{column.header}</span>
|
|
165
|
-
{getSortIcon(column.key)}
|
|
166
|
-
</button>
|
|
167
|
-
) : (
|
|
168
|
-
column.header
|
|
169
|
-
)}
|
|
170
|
-
</th>
|
|
171
|
-
))}
|
|
172
|
-
</tr>
|
|
173
|
-
</thead>
|
|
174
|
-
<tbody>
|
|
175
|
-
{data.map((row) => {
|
|
176
|
-
const rowKey = keyExtractor(row);
|
|
177
|
-
const isSelected = selectedRows.has(rowKey);
|
|
178
|
-
const isExpanded = expandedRows.has(rowKey);
|
|
179
|
-
|
|
180
|
-
return (
|
|
181
|
-
<React.Fragment key={rowKey}>
|
|
182
|
-
<tr className={`table-row ${isSelected ? 'bg-accent-50 border-l-2 border-accent-500' : ''}`}>
|
|
183
|
-
{/* Selection Checkbox */}
|
|
184
|
-
{selectable && (
|
|
185
|
-
<td className="table-cell">
|
|
186
|
-
<input
|
|
187
|
-
type="checkbox"
|
|
188
|
-
checked={isSelected}
|
|
189
|
-
onChange={() => handleRowSelect(rowKey)}
|
|
190
|
-
className="w-4 h-4 text-accent-600 border-paper-300 rounded focus:ring-accent-400"
|
|
191
|
-
aria-label={`Select row ${rowKey}`}
|
|
192
|
-
/>
|
|
193
|
-
</td>
|
|
194
|
-
)}
|
|
195
|
-
|
|
196
|
-
{/* Expand Button */}
|
|
197
|
-
{expandable && (
|
|
198
|
-
<td className="table-cell">
|
|
199
|
-
<button
|
|
200
|
-
onClick={() => handleRowExpand(rowKey)}
|
|
201
|
-
className="text-ink-500 hover:text-ink-900 transition-colors"
|
|
202
|
-
aria-label={isExpanded ? 'Collapse row' : 'Expand row'}
|
|
203
|
-
>
|
|
204
|
-
{isExpanded ? (
|
|
205
|
-
<ChevronDown className="h-4 w-4" />
|
|
206
|
-
) : (
|
|
207
|
-
<ChevronRight className="h-4 w-4" />
|
|
208
|
-
)}
|
|
209
|
-
</button>
|
|
210
|
-
</td>
|
|
211
|
-
)}
|
|
212
|
-
|
|
213
|
-
{/* Data Cells */}
|
|
214
|
-
{columns.map((column) => (
|
|
215
|
-
<td key={column.key} className="table-cell">
|
|
216
|
-
{column.accessor ? column.accessor(row) : (row as any)[column.key]}
|
|
217
|
-
</td>
|
|
218
|
-
))}
|
|
219
|
-
</tr>
|
|
220
|
-
|
|
221
|
-
{/* Expanded Row Content */}
|
|
222
|
-
{expandable && isExpanded && renderExpandedRow && (
|
|
223
|
-
<tr>
|
|
224
|
-
<td
|
|
225
|
-
colSpan={columns.length + (selectable ? 1 : 0) + (expandable ? 1 : 0)}
|
|
226
|
-
className="px-6 py-4 bg-paper-50"
|
|
227
|
-
>
|
|
228
|
-
{renderExpandedRow(row)}
|
|
229
|
-
</td>
|
|
230
|
-
</tr>
|
|
231
|
-
)}
|
|
232
|
-
</React.Fragment>
|
|
233
|
-
);
|
|
234
|
-
})}
|
|
235
|
-
</tbody>
|
|
236
|
-
</table>
|
|
237
|
-
</div>
|
|
238
|
-
);
|
|
239
|
-
}
|