@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.
Files changed (55) hide show
  1. package/dist/components/Box.d.ts +2 -1
  2. package/dist/components/Box.d.ts.map +1 -1
  3. package/dist/components/Button.d.ts +10 -1
  4. package/dist/components/Button.d.ts.map +1 -1
  5. package/dist/components/Card.d.ts +11 -2
  6. package/dist/components/Card.d.ts.map +1 -1
  7. package/dist/components/DataTable.d.ts +17 -3
  8. package/dist/components/DataTable.d.ts.map +1 -1
  9. package/dist/components/EmptyState.d.ts +3 -1
  10. package/dist/components/EmptyState.d.ts.map +1 -1
  11. package/dist/components/Grid.d.ts +4 -2
  12. package/dist/components/Grid.d.ts.map +1 -1
  13. package/dist/components/Input.d.ts +2 -0
  14. package/dist/components/Input.d.ts.map +1 -1
  15. package/dist/components/MultiSelect.d.ts +13 -1
  16. package/dist/components/MultiSelect.d.ts.map +1 -1
  17. package/dist/components/Spreadsheet.d.ts +5 -1
  18. package/dist/components/Spreadsheet.d.ts.map +1 -1
  19. package/dist/components/Stack.d.ts +25 -5
  20. package/dist/components/Stack.d.ts.map +1 -1
  21. package/dist/components/Text.d.ts +20 -4
  22. package/dist/components/Text.d.ts.map +1 -1
  23. package/dist/components/Textarea.d.ts +2 -0
  24. package/dist/components/Textarea.d.ts.map +1 -1
  25. package/dist/components/index.d.ts +1 -3
  26. package/dist/components/index.d.ts.map +1 -1
  27. package/dist/index.d.ts +115 -49
  28. package/dist/index.esm.js +187 -8563
  29. package/dist/index.esm.js.map +1 -1
  30. package/dist/index.js +186 -8563
  31. package/dist/index.js.map +1 -1
  32. package/dist/styles.css +8 -51
  33. package/package.json +4 -4
  34. package/src/components/Box.stories.tsx +377 -0
  35. package/src/components/Box.tsx +8 -4
  36. package/src/components/Button.tsx +23 -10
  37. package/src/components/Card.tsx +20 -5
  38. package/src/components/DataTable.stories.tsx +36 -25
  39. package/src/components/DataTable.tsx +95 -5
  40. package/src/components/EmptyState.stories.tsx +124 -72
  41. package/src/components/EmptyState.tsx +10 -0
  42. package/src/components/Grid.stories.tsx +348 -0
  43. package/src/components/Grid.tsx +12 -5
  44. package/src/components/Input.tsx +12 -2
  45. package/src/components/MultiSelect.tsx +41 -10
  46. package/src/components/Spreadsheet.tsx +8 -57
  47. package/src/components/Stack.stories.tsx +24 -1
  48. package/src/components/Stack.tsx +40 -10
  49. package/src/components/Text.stories.tsx +273 -0
  50. package/src/components/Text.tsx +33 -8
  51. package/src/components/Textarea.tsx +32 -21
  52. package/src/components/index.ts +1 -4
  53. package/dist/components/Table.d.ts +0 -26
  54. package/dist/components/Table.d.ts.map +0 -1
  55. package/src/components/Table.tsx +0 -239
@@ -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
- }