@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.
Files changed (37) hide show
  1. package/README.md +3 -3
  2. package/dist/components/ActionBar.d.ts +112 -0
  3. package/dist/components/ActionBar.d.ts.map +1 -0
  4. package/dist/components/DataGrid.d.ts +182 -0
  5. package/dist/components/DataGrid.d.ts.map +1 -0
  6. package/dist/components/FormulaAutocomplete.d.ts +29 -0
  7. package/dist/components/FormulaAutocomplete.d.ts.map +1 -0
  8. package/dist/components/Modal.d.ts +29 -1
  9. package/dist/components/Modal.d.ts.map +1 -1
  10. package/dist/components/PageHeader.d.ts +86 -0
  11. package/dist/components/PageHeader.d.ts.map +1 -0
  12. package/dist/components/Select.d.ts +2 -0
  13. package/dist/components/Select.d.ts.map +1 -1
  14. package/dist/components/index.d.ts +8 -0
  15. package/dist/components/index.d.ts.map +1 -1
  16. package/dist/index.d.ts +419 -3
  17. package/dist/index.esm.js +2533 -350
  18. package/dist/index.esm.js.map +1 -1
  19. package/dist/index.js +2543 -348
  20. package/dist/index.js.map +1 -1
  21. package/dist/styles.css +81 -0
  22. package/dist/utils/formulaDefinitions.d.ts +25 -0
  23. package/dist/utils/formulaDefinitions.d.ts.map +1 -0
  24. package/package.json +1 -1
  25. package/src/components/ActionBar.stories.tsx +246 -0
  26. package/src/components/ActionBar.tsx +242 -0
  27. package/src/components/DataGrid.stories.tsx +356 -0
  28. package/src/components/DataGrid.tsx +1025 -0
  29. package/src/components/FormulaAutocomplete.tsx +417 -0
  30. package/src/components/Modal.stories.tsx +205 -0
  31. package/src/components/Modal.tsx +38 -1
  32. package/src/components/PageHeader.stories.tsx +198 -0
  33. package/src/components/PageHeader.tsx +217 -0
  34. package/src/components/Select.tsx +121 -7
  35. package/src/components/Sidebar.tsx +2 -2
  36. package/src/components/index.ts +36 -0
  37. 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
+ };