@papernote/ui 1.5.0 → 1.7.0
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/README.md +3 -3
- package/dist/components/ActionBar.d.ts +112 -0
- package/dist/components/ActionBar.d.ts.map +1 -0
- package/dist/components/DataGrid.d.ts +182 -0
- package/dist/components/DataGrid.d.ts.map +1 -0
- package/dist/components/FormulaAutocomplete.d.ts +29 -0
- package/dist/components/FormulaAutocomplete.d.ts.map +1 -0
- package/dist/components/Modal.d.ts +29 -1
- package/dist/components/Modal.d.ts.map +1 -1
- package/dist/components/PageHeader.d.ts +86 -0
- package/dist/components/PageHeader.d.ts.map +1 -0
- package/dist/components/Select.d.ts +2 -0
- package/dist/components/Select.d.ts.map +1 -1
- package/dist/components/index.d.ts +8 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/index.d.ts +419 -3
- package/dist/index.esm.js +2533 -350
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +2543 -348
- package/dist/index.js.map +1 -1
- package/dist/styles.css +81 -0
- package/dist/utils/formulaDefinitions.d.ts +25 -0
- package/dist/utils/formulaDefinitions.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/components/ActionBar.stories.tsx +246 -0
- package/src/components/ActionBar.tsx +242 -0
- package/src/components/DataGrid.stories.tsx +356 -0
- package/src/components/DataGrid.tsx +1025 -0
- package/src/components/FormulaAutocomplete.tsx +417 -0
- package/src/components/Modal.stories.tsx +205 -0
- package/src/components/Modal.tsx +38 -1
- package/src/components/PageHeader.stories.tsx +198 -0
- package/src/components/PageHeader.tsx +217 -0
- package/src/components/Select.tsx +121 -7
- package/src/components/Sidebar.tsx +2 -2
- package/src/components/index.ts +36 -0
- package/src/utils/formulaDefinitions.ts +1228 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { DataGrid, DataGridCell, DataGridColumn } from './DataGrid';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof DataGrid> = {
|
|
5
|
+
title: 'Components/DataGrid',
|
|
6
|
+
component: DataGrid,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'padded',
|
|
9
|
+
docs: {
|
|
10
|
+
description: {
|
|
11
|
+
component: `
|
|
12
|
+
DataGrid is an Excel-like spreadsheet component with formula support and intellisense.
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
- **280+ Excel formulas** via fast-formula-parser (MIT licensed)
|
|
16
|
+
- **Formula Intellisense** - Autocomplete with function signatures and parameter hints
|
|
17
|
+
- **Sorting & Filtering** - Click column headers
|
|
18
|
+
- **Frozen rows/columns** - Keep headers visible while scrolling
|
|
19
|
+
- **Cell editing** - Double-click to edit
|
|
20
|
+
- **Keyboard navigation** - Arrow keys, Enter, Escape, Tab
|
|
21
|
+
- **Zebra striping** - Alternating row colors
|
|
22
|
+
- **CSV Export** - Export data to CSV
|
|
23
|
+
|
|
24
|
+
## Formula Intellisense
|
|
25
|
+
When editing a cell with \`formulas={true}\`:
|
|
26
|
+
1. Type \`=\` to see all available formulas
|
|
27
|
+
2. Start typing a function name to filter (e.g., \`=SUM\`, \`=VL\`)
|
|
28
|
+
3. Use category tabs to browse (Math, Lookup, Text, Logical, Date, etc.)
|
|
29
|
+
4. Arrow keys navigate, Tab/Enter inserts the function
|
|
30
|
+
5. After inserting, see parameter hints showing what each argument means
|
|
31
|
+
|
|
32
|
+
## Supported Formulas
|
|
33
|
+
**Math:** SUM, AVERAGE, MIN, MAX, COUNT, ROUND, ABS, SQRT, PRODUCT, MOD...
|
|
34
|
+
**Lookup:** VLOOKUP, HLOOKUP, INDEX, MATCH, CHOOSE, OFFSET, INDIRECT...
|
|
35
|
+
**Text:** CONCATENATE, LEFT, RIGHT, MID, LEN, UPPER, LOWER, TRIM...
|
|
36
|
+
**Logical:** IF, IFS, AND, OR, NOT, IFERROR, SWITCH...
|
|
37
|
+
**Date:** TODAY, NOW, DATE, YEAR, MONTH, DAY, DATEDIF, NETWORKDAYS...
|
|
38
|
+
**Statistical:** COUNTIF, SUMIF, AVERAGEIF, MEDIAN, STDEV, RANK...
|
|
39
|
+
**Financial:** PMT, PV, FV, NPV, IRR, RATE...
|
|
40
|
+
|
|
41
|
+
## Frozen Rows
|
|
42
|
+
- \`'none'\` - No frozen rows
|
|
43
|
+
- \`'first'\` - Freeze first row (common for headers)
|
|
44
|
+
- \`'selected'\` - Freeze the currently selected row
|
|
45
|
+
- \`number\` - Freeze specific number of rows
|
|
46
|
+
`,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
tags: ['autodocs'],
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default meta;
|
|
54
|
+
type Story = StoryObj<typeof DataGrid>;
|
|
55
|
+
|
|
56
|
+
// Sample data
|
|
57
|
+
const basicColumns: DataGridColumn[] = [
|
|
58
|
+
{ key: 'name', header: 'Name', width: 150, sortable: true, filterable: true },
|
|
59
|
+
{ key: 'age', header: 'Age', width: 80, type: 'number', sortable: true, align: 'right' },
|
|
60
|
+
{ key: 'city', header: 'City', width: 150, sortable: true, filterable: true },
|
|
61
|
+
{ key: 'country', header: 'Country', width: 120, sortable: true },
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
const basicData: DataGridCell[][] = [
|
|
65
|
+
[{ value: 'John Smith' }, { value: 32 }, { value: 'New York' }, { value: 'USA' }],
|
|
66
|
+
[{ value: 'Jane Doe' }, { value: 28 }, { value: 'Los Angeles' }, { value: 'USA' }],
|
|
67
|
+
[{ value: 'Bob Johnson' }, { value: 45 }, { value: 'Chicago' }, { value: 'USA' }],
|
|
68
|
+
[{ value: 'Alice Brown' }, { value: 36 }, { value: 'Houston' }, { value: 'USA' }],
|
|
69
|
+
[{ value: 'Charlie Wilson' }, { value: 29 }, { value: 'Phoenix' }, { value: 'USA' }],
|
|
70
|
+
[{ value: 'Diana Miller' }, { value: 41 }, { value: 'Philadelphia' }, { value: 'USA' }],
|
|
71
|
+
[{ value: 'Edward Davis' }, { value: 33 }, { value: 'San Antonio' }, { value: 'USA' }],
|
|
72
|
+
[{ value: 'Fiona Garcia' }, { value: 27 }, { value: 'San Diego' }, { value: 'USA' }],
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
const salesColumns: DataGridColumn[] = [
|
|
76
|
+
{ key: 'product', header: 'Product', width: 150 },
|
|
77
|
+
{ key: 'q1', header: 'Q1', width: 100, type: 'number', align: 'right' },
|
|
78
|
+
{ key: 'q2', header: 'Q2', width: 100, type: 'number', align: 'right' },
|
|
79
|
+
{ key: 'q3', header: 'Q3', width: 100, type: 'number', align: 'right' },
|
|
80
|
+
{ key: 'q4', header: 'Q4', width: 100, type: 'number', align: 'right' },
|
|
81
|
+
{ key: 'total', header: 'Total', width: 120, type: 'number', align: 'right' },
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
const salesData: DataGridCell[][] = [
|
|
85
|
+
[
|
|
86
|
+
{ value: 'Widget A' },
|
|
87
|
+
{ value: 1200 },
|
|
88
|
+
{ value: 1350 },
|
|
89
|
+
{ value: 1100 },
|
|
90
|
+
{ value: 1500 },
|
|
91
|
+
{ value: 0, formula: '=SUM(B1:E1)' },
|
|
92
|
+
],
|
|
93
|
+
[
|
|
94
|
+
{ value: 'Widget B' },
|
|
95
|
+
{ value: 800 },
|
|
96
|
+
{ value: 950 },
|
|
97
|
+
{ value: 1200 },
|
|
98
|
+
{ value: 1100 },
|
|
99
|
+
{ value: 0, formula: '=SUM(B2:E2)' },
|
|
100
|
+
],
|
|
101
|
+
[
|
|
102
|
+
{ value: 'Widget C' },
|
|
103
|
+
{ value: 2100 },
|
|
104
|
+
{ value: 1800 },
|
|
105
|
+
{ value: 2200 },
|
|
106
|
+
{ value: 2400 },
|
|
107
|
+
{ value: 0, formula: '=SUM(B3:E3)' },
|
|
108
|
+
],
|
|
109
|
+
[
|
|
110
|
+
{ value: 'Widget D' },
|
|
111
|
+
{ value: 650 },
|
|
112
|
+
{ value: 720 },
|
|
113
|
+
{ value: 680 },
|
|
114
|
+
{ value: 750 },
|
|
115
|
+
{ value: 0, formula: '=SUM(B4:E4)' },
|
|
116
|
+
],
|
|
117
|
+
[
|
|
118
|
+
{ value: 'Total', readOnly: true },
|
|
119
|
+
{ value: 0, formula: '=SUM(B1:B4)' },
|
|
120
|
+
{ value: 0, formula: '=SUM(C1:C4)' },
|
|
121
|
+
{ value: 0, formula: '=SUM(D1:D4)' },
|
|
122
|
+
{ value: 0, formula: '=SUM(E1:E4)' },
|
|
123
|
+
{ value: 0, formula: '=SUM(F1:F4)' },
|
|
124
|
+
],
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
const flightLogColumns: DataGridColumn[] = [
|
|
128
|
+
{ key: 'date', header: 'Date', width: 100, sortable: true },
|
|
129
|
+
{ key: 'aircraft', header: 'Aircraft', width: 120, sortable: true, filterable: true },
|
|
130
|
+
{ key: 'registration', header: 'Registration', width: 100 },
|
|
131
|
+
{ key: 'departure', header: 'Departure', width: 90 },
|
|
132
|
+
{ key: 'arrival', header: 'Arrival', width: 90 },
|
|
133
|
+
{ key: 'flightTime', header: 'Flight Time', width: 100, type: 'number', align: 'right' },
|
|
134
|
+
{ key: 'passengers', header: 'Passengers', width: 100, type: 'number', align: 'right' },
|
|
135
|
+
{ key: 'pilot', header: 'Pilot', width: 120, sortable: true, filterable: true },
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
const flightLogData: DataGridCell[][] = [
|
|
139
|
+
[{ value: '2024-01-15' }, { value: 'Cessna 172' }, { value: 'N12345' }, { value: 'KJFK' }, { value: 'KBOS' }, { value: 2.5 }, { value: 3 }, { value: 'John Smith' }],
|
|
140
|
+
[{ value: '2024-01-16' }, { value: 'Piper PA-28' }, { value: 'N67890' }, { value: 'KBOS' }, { value: 'KPHL' }, { value: 1.8 }, { value: 2 }, { value: 'Jane Doe' }],
|
|
141
|
+
[{ value: '2024-01-17' }, { value: 'Cessna 182' }, { value: 'N11111' }, { value: 'KPHL' }, { value: 'KDCA' }, { value: 1.2 }, { value: 4 }, { value: 'Bob Johnson' }],
|
|
142
|
+
[{ value: '2024-01-18' }, { value: 'Beechcraft Baron' }, { value: 'N22222' }, { value: 'KDCA' }, { value: 'KATL' }, { value: 2.1 }, { value: 5 }, { value: 'Alice Brown' }],
|
|
143
|
+
[{ value: '2024-01-19' }, { value: 'Cessna 172' }, { value: 'N12345' }, { value: 'KATL' }, { value: 'KMIA' }, { value: 2.8 }, { value: 3 }, { value: 'John Smith' }],
|
|
144
|
+
[{ value: '2024-01-20' }, { value: 'Piper PA-28' }, { value: 'N67890' }, { value: 'KMIA' }, { value: 'KTPA' }, { value: 0.9 }, { value: 2 }, { value: 'Charlie Wilson' }],
|
|
145
|
+
[{ value: '2024-01-21' }, { value: 'Cessna 182' }, { value: 'N11111' }, { value: 'KTPA' }, { value: 'KJAX' }, { value: 1.1 }, { value: 4 }, { value: 'Diana Miller' }],
|
|
146
|
+
[{ value: '2024-01-22' }, { value: 'Beechcraft Baron' }, { value: 'N22222' }, { value: 'KJAX' }, { value: 'KCLT' }, { value: 1.7 }, { value: 5 }, { value: 'Edward Davis' }],
|
|
147
|
+
[{ value: '2024-01-23' }, { value: 'Cessna 172' }, { value: 'N12345' }, { value: 'KCLT' }, { value: 'KRDU' }, { value: 0.8 }, { value: 3 }, { value: 'Fiona Garcia' }],
|
|
148
|
+
[{ value: '2024-01-24' }, { value: 'Piper PA-28' }, { value: 'N67890' }, { value: 'KRDU' }, { value: 'KRIC' }, { value: 0.6 }, { value: 2 }, { value: 'John Smith' }],
|
|
149
|
+
];
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Basic grid with sorting and filtering
|
|
153
|
+
*/
|
|
154
|
+
export const Basic: Story = {
|
|
155
|
+
args: {
|
|
156
|
+
data: basicData,
|
|
157
|
+
columns: basicColumns,
|
|
158
|
+
rowHeaders: true,
|
|
159
|
+
height: 350,
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* With Excel formulas - demonstrates SUM and cell references
|
|
165
|
+
*
|
|
166
|
+
* **Formula Intellisense:**
|
|
167
|
+
* - Double-click any cell and type `=` to see formula autocomplete
|
|
168
|
+
* - Use arrow keys to navigate, Tab/Enter to insert
|
|
169
|
+
* - Browse by category (Math, Lookup, Text, etc.)
|
|
170
|
+
* - See parameter hints as you type
|
|
171
|
+
*
|
|
172
|
+
* Try typing `=SUM(`, `=VLOOKUP(`, `=IF(` etc.
|
|
173
|
+
*/
|
|
174
|
+
export const WithFormulas: Story = {
|
|
175
|
+
args: {
|
|
176
|
+
data: salesData,
|
|
177
|
+
columns: salesColumns,
|
|
178
|
+
formulas: true,
|
|
179
|
+
rowHeaders: true,
|
|
180
|
+
height: 300,
|
|
181
|
+
showToolbar: true,
|
|
182
|
+
title: 'Quarterly Sales Report',
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Frozen first row - header stays visible while scrolling
|
|
188
|
+
*/
|
|
189
|
+
export const FrozenFirstRow: Story = {
|
|
190
|
+
args: {
|
|
191
|
+
data: flightLogData,
|
|
192
|
+
columns: flightLogColumns,
|
|
193
|
+
frozenRows: 'first',
|
|
194
|
+
rowHeaders: true,
|
|
195
|
+
zebraStripes: true,
|
|
196
|
+
height: 300,
|
|
197
|
+
showToolbar: true,
|
|
198
|
+
title: 'Flight Log',
|
|
199
|
+
showFreezeRowToggle: true,
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Frozen columns - first column stays visible while scrolling horizontally
|
|
205
|
+
*/
|
|
206
|
+
export const FrozenColumns: Story = {
|
|
207
|
+
args: {
|
|
208
|
+
data: flightLogData,
|
|
209
|
+
columns: flightLogColumns,
|
|
210
|
+
frozenColumns: 2,
|
|
211
|
+
rowHeaders: true,
|
|
212
|
+
zebraStripes: true,
|
|
213
|
+
height: 300,
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Read-only data viewer with zebra stripes
|
|
219
|
+
*/
|
|
220
|
+
export const ReadOnlyViewer: Story = {
|
|
221
|
+
args: {
|
|
222
|
+
data: flightLogData,
|
|
223
|
+
columns: flightLogColumns,
|
|
224
|
+
readOnly: true,
|
|
225
|
+
zebraStripes: true,
|
|
226
|
+
rowHeaders: true,
|
|
227
|
+
height: 350,
|
|
228
|
+
showToolbar: true,
|
|
229
|
+
title: 'Flight Log Viewer',
|
|
230
|
+
enableExport: true,
|
|
231
|
+
exportFileName: 'flight-log.csv',
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* With toolbar - export and save functionality
|
|
237
|
+
*/
|
|
238
|
+
export const WithToolbar: Story = {
|
|
239
|
+
args: {
|
|
240
|
+
data: salesData,
|
|
241
|
+
columns: salesColumns,
|
|
242
|
+
formulas: true,
|
|
243
|
+
showToolbar: true,
|
|
244
|
+
title: 'Sales Dashboard',
|
|
245
|
+
enableExport: true,
|
|
246
|
+
enableSave: true,
|
|
247
|
+
showFreezeRowToggle: true,
|
|
248
|
+
onSave: async (data) => {
|
|
249
|
+
console.log('Saving data:', data);
|
|
250
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
251
|
+
},
|
|
252
|
+
height: 250,
|
|
253
|
+
},
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Compact density - more data in less space
|
|
258
|
+
*/
|
|
259
|
+
export const CompactDensity: Story = {
|
|
260
|
+
args: {
|
|
261
|
+
data: flightLogData,
|
|
262
|
+
columns: flightLogColumns,
|
|
263
|
+
density: 'compact',
|
|
264
|
+
zebraStripes: true,
|
|
265
|
+
rowHeaders: true,
|
|
266
|
+
height: 300,
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Comfortable density - more space between rows
|
|
272
|
+
*/
|
|
273
|
+
export const ComfortableDensity: Story = {
|
|
274
|
+
args: {
|
|
275
|
+
data: basicData,
|
|
276
|
+
columns: basicColumns,
|
|
277
|
+
density: 'comfortable',
|
|
278
|
+
zebraStripes: true,
|
|
279
|
+
rowHeaders: true,
|
|
280
|
+
height: 400,
|
|
281
|
+
},
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Editable grid - double-click to edit cells
|
|
286
|
+
*/
|
|
287
|
+
export const Editable: Story = {
|
|
288
|
+
args: {
|
|
289
|
+
data: [
|
|
290
|
+
[{ value: 'Task 1' }, { value: 'In Progress' }, { value: 'High' }, { value: '2024-02-01' }],
|
|
291
|
+
[{ value: 'Task 2' }, { value: 'Done' }, { value: 'Medium' }, { value: '2024-01-28' }],
|
|
292
|
+
[{ value: 'Task 3' }, { value: 'Pending' }, { value: 'Low' }, { value: '2024-02-05' }],
|
|
293
|
+
[{ value: '' }, { value: '' }, { value: '' }, { value: '' }],
|
|
294
|
+
[{ value: '' }, { value: '' }, { value: '' }, { value: '' }],
|
|
295
|
+
],
|
|
296
|
+
columns: [
|
|
297
|
+
{ key: 'task', header: 'Task', width: 200 },
|
|
298
|
+
{ key: 'status', header: 'Status', width: 120 },
|
|
299
|
+
{ key: 'priority', header: 'Priority', width: 100 },
|
|
300
|
+
{ key: 'dueDate', header: 'Due Date', width: 120 },
|
|
301
|
+
],
|
|
302
|
+
rowHeaders: true,
|
|
303
|
+
height: 250,
|
|
304
|
+
onChange: (data, row, col) => {
|
|
305
|
+
console.log(`Cell changed at row ${row}, col ${col}:`, data[row][col]);
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Full featured example - all features enabled
|
|
312
|
+
*/
|
|
313
|
+
export const FullFeatured: Story = {
|
|
314
|
+
args: {
|
|
315
|
+
data: salesData,
|
|
316
|
+
columns: salesColumns,
|
|
317
|
+
formulas: true,
|
|
318
|
+
frozenRows: 'first',
|
|
319
|
+
frozenColumns: 1,
|
|
320
|
+
zebraStripes: true,
|
|
321
|
+
rowHeaders: true,
|
|
322
|
+
showToolbar: true,
|
|
323
|
+
title: 'Full Featured DataGrid',
|
|
324
|
+
enableExport: true,
|
|
325
|
+
enableSave: true,
|
|
326
|
+
showFreezeRowToggle: true,
|
|
327
|
+
onSave: async (data) => {
|
|
328
|
+
console.log('Saving:', data);
|
|
329
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
330
|
+
},
|
|
331
|
+
height: 300,
|
|
332
|
+
},
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Currency formatting example
|
|
337
|
+
*/
|
|
338
|
+
export const CurrencyFormatting: Story = {
|
|
339
|
+
args: {
|
|
340
|
+
data: [
|
|
341
|
+
[{ value: 'Product A' }, { value: 1234.56 }, { value: 100 }, { value: 0, formula: '=B1*C1' }],
|
|
342
|
+
[{ value: 'Product B' }, { value: 789.99 }, { value: 50 }, { value: 0, formula: '=B2*C2' }],
|
|
343
|
+
[{ value: 'Product C' }, { value: 2345.00 }, { value: 75 }, { value: 0, formula: '=B3*C3' }],
|
|
344
|
+
[{ value: 'Total' }, { value: 0, formula: '=SUM(B1:B3)' }, { value: 0, formula: '=SUM(C1:C3)' }, { value: 0, formula: '=SUM(D1:D3)' }],
|
|
345
|
+
],
|
|
346
|
+
columns: [
|
|
347
|
+
{ key: 'product', header: 'Product', width: 150 },
|
|
348
|
+
{ key: 'price', header: 'Price', width: 120, type: 'currency', align: 'right' },
|
|
349
|
+
{ key: 'qty', header: 'Quantity', width: 100, type: 'number', align: 'right' },
|
|
350
|
+
{ key: 'total', header: 'Total', width: 150, type: 'currency', align: 'right' },
|
|
351
|
+
],
|
|
352
|
+
formulas: true,
|
|
353
|
+
rowHeaders: true,
|
|
354
|
+
height: 220,
|
|
355
|
+
},
|
|
356
|
+
};
|