@lapis-notes/csv 0.0.0-stage → 0.2.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 (105) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/LICENSE.md +4 -0
  3. package/README.md +19 -2
  4. package/dist/app.css +210 -0
  5. package/dist/csv-settings.d.ts +13 -0
  6. package/dist/csv-settings.js +28 -0
  7. package/dist/index.d.ts +7 -0
  8. package/dist/index.js +7 -0
  9. package/dist/lib/CsvSheet.svelte +58 -0
  10. package/dist/lib/CsvSheet.svelte.d.ts +11 -0
  11. package/dist/lib/CsvTable.svelte +58 -0
  12. package/dist/lib/CsvTable.svelte.d.ts +11 -0
  13. package/dist/lib/codemirror/csv-language-extensions.d.ts +3 -0
  14. package/dist/lib/codemirror/csv-language-extensions.js +11 -0
  15. package/dist/lib/codemirror/csv-language.d.ts +3 -0
  16. package/dist/lib/codemirror/csv-language.js +24 -0
  17. package/dist/lib/codemirror/csv-rainbow-theme.d.ts +3 -0
  18. package/dist/lib/codemirror/csv-rainbow-theme.js +15 -0
  19. package/dist/lib/codemirror/csv-source-extensions.d.ts +7 -0
  20. package/dist/lib/codemirror/csv-source-extensions.js +9 -0
  21. package/dist/lib/codemirror/csv.parser.d.ts +2 -0
  22. package/dist/lib/codemirror/csv.parser.js +16 -0
  23. package/dist/lib/codemirror/csv.parser.terms.d.ts +1 -0
  24. package/dist/lib/codemirror/csv.parser.terms.js +2 -0
  25. package/dist/lib/codemirror/syntax.grammar +36 -0
  26. package/dist/lib/components/csv-cell.svelte +137 -0
  27. package/dist/lib/components/csv-cell.svelte.d.ts +11 -0
  28. package/dist/lib/components/csv-data-table-column-head.svelte +76 -0
  29. package/dist/lib/components/csv-data-table-column-head.svelte.d.ts +17 -0
  30. package/dist/lib/components/csv-data-table-column-header.svelte +159 -0
  31. package/dist/lib/components/csv-data-table-column-header.svelte.d.ts +23 -0
  32. package/dist/lib/components/csv-data-table-data-cell.svelte +72 -0
  33. package/dist/lib/components/csv-data-table-data-cell.svelte.d.ts +18 -0
  34. package/dist/lib/components/csv-data-table-drag-overlay.svelte +119 -0
  35. package/dist/lib/components/csv-data-table-drag-overlay.svelte.d.ts +13 -0
  36. package/dist/lib/components/csv-data-table-row-actions.svelte +47 -0
  37. package/dist/lib/components/csv-data-table-row-actions.svelte.d.ts +8 -0
  38. package/dist/lib/components/csv-data-table-row-grip-cell.svelte +102 -0
  39. package/dist/lib/components/csv-data-table-row-grip-cell.svelte.d.ts +19 -0
  40. package/dist/lib/components/csv-data-table-row.svelte +38 -0
  41. package/dist/lib/components/csv-data-table-row.svelte.d.ts +11 -0
  42. package/dist/lib/components/csv-data-table.svelte +903 -0
  43. package/dist/lib/components/csv-data-table.svelte.d.ts +21 -0
  44. package/dist/lib/components/csv-find.svelte +382 -0
  45. package/dist/lib/components/csv-find.svelte.d.ts +24 -0
  46. package/dist/lib/components/csv-row-virtualizer.svelte.d.ts +9 -0
  47. package/dist/lib/components/csv-row-virtualizer.svelte.js +59 -0
  48. package/dist/lib/components/csv-source-view.svelte +127 -0
  49. package/dist/lib/components/csv-source-view.svelte.d.ts +10 -0
  50. package/dist/lib/components/csv-status-bar.svelte +101 -0
  51. package/dist/lib/components/csv-status-bar.svelte.d.ts +14 -0
  52. package/dist/lib/components/csv-table-dnd.d.ts +9 -0
  53. package/dist/lib/components/csv-table-dnd.js +12 -0
  54. package/dist/lib/components/csv-table-drag-measure.d.ts +7 -0
  55. package/dist/lib/components/csv-table-drag-measure.js +38 -0
  56. package/dist/lib/components/csv-table-selection.d.ts +28 -0
  57. package/dist/lib/components/csv-table-selection.js +178 -0
  58. package/dist/lib/components/csv-table-view.svelte +265 -0
  59. package/dist/lib/components/csv-table-view.svelte.d.ts +16 -0
  60. package/dist/lib/csv-plugin.d.ts +9 -0
  61. package/dist/lib/csv-plugin.js +107 -0
  62. package/dist/lib/csv-view-settings.d.ts +43 -0
  63. package/dist/lib/csv-view-settings.js +86 -0
  64. package/dist/lib/ids.d.ts +8 -0
  65. package/dist/lib/ids.js +19 -0
  66. package/dist/lib/model/csv-column-sort.d.ts +16 -0
  67. package/dist/lib/model/csv-column-sort.js +81 -0
  68. package/dist/lib/model/csv-grid.d.ts +31 -0
  69. package/dist/lib/model/csv-grid.js +161 -0
  70. package/dist/lib/model/csv-search.d.ts +38 -0
  71. package/dist/lib/model/csv-search.js +101 -0
  72. package/dist/lib/model/csv-table-model.d.ts +10 -0
  73. package/dist/lib/model/csv-table-model.js +18 -0
  74. package/dist/lib/model/parse-csv.d.ts +10 -0
  75. package/dist/lib/model/parse-csv.js +13 -0
  76. package/dist/lib/model/serialize-csv.d.ts +5 -0
  77. package/dist/lib/model/serialize-csv.js +10 -0
  78. package/dist/lib/sheet/csv-sheet-toolbar.svelte +244 -0
  79. package/dist/lib/sheet/csv-sheet-toolbar.svelte.d.ts +20 -0
  80. package/dist/lib/sheet/csv-sheet-view.svelte +444 -0
  81. package/dist/lib/sheet/csv-sheet-view.svelte.d.ts +18 -0
  82. package/dist/lib/sheet/csv-sheet.svelte +1121 -0
  83. package/dist/lib/sheet/csv-sheet.svelte.d.ts +37 -0
  84. package/dist/lib/sheet/sheet-glyph.svelte +57 -0
  85. package/dist/lib/sheet/sheet-glyph.svelte.d.ts +7 -0
  86. package/dist/lib/sheet/sheet-history.d.ts +14 -0
  87. package/dist/lib/sheet/sheet-history.js +33 -0
  88. package/dist/lib/sheet/sheet-layout.d.ts +121 -0
  89. package/dist/lib/sheet/sheet-layout.js +336 -0
  90. package/dist/lib/sheet/sheet-paint.d.ts +45 -0
  91. package/dist/lib/sheet/sheet-paint.js +274 -0
  92. package/dist/lib/sheet/sheet-theme.d.ts +2 -0
  93. package/dist/lib/sheet/sheet-theme.js +26 -0
  94. package/dist/lib/views/csv-view-mode.d.ts +3 -0
  95. package/dist/lib/views/csv-view-mode.js +6 -0
  96. package/dist/lib/views/csv-view.d.ts +24 -0
  97. package/dist/lib/views/csv-view.js +125 -0
  98. package/dist/styles/csv-find.css +313 -0
  99. package/dist/styles/csv-table.css +882 -0
  100. package/dist/styles.css +37 -0
  101. package/manifest.json +45 -0
  102. package/package.json +86 -3
  103. package/registry-content/overview.md +3 -0
  104. package/registry.json +322 -0
  105. package/styles.css +1 -0
@@ -0,0 +1,101 @@
1
+ import { SearchQuery } from "@codemirror/search";
2
+ import { EditorState } from "@codemirror/state";
3
+ export function csvSearchQuery(options) {
4
+ return new SearchQuery({
5
+ search: options.search,
6
+ replace: options.replace ?? "",
7
+ caseSensitive: options.caseSensitive ?? false,
8
+ wholeWord: options.wholeWord ?? false,
9
+ regexp: options.regexp ?? false,
10
+ });
11
+ }
12
+ /** Matches in row-major order. An empty or invalid query matches nothing. */
13
+ export function csvCellMatches(rows, query) {
14
+ if (!query.search || !query.valid)
15
+ return [];
16
+ const matches = [];
17
+ rows.forEach((row, rowIndex) => {
18
+ row.forEach((cell, colIndex) => {
19
+ const cursor = query.getCursor(EditorState.create({ doc: cell }).doc);
20
+ for (let next = cursor.next(); !next.done; next = cursor.next()) {
21
+ matches.push({
22
+ row: rowIndex,
23
+ col: colIndex,
24
+ from: next.value.from,
25
+ to: next.value.to,
26
+ });
27
+ }
28
+ });
29
+ });
30
+ return matches;
31
+ }
32
+ export function csvDocumentMatches(doc, query) {
33
+ if (!query.search || !query.valid)
34
+ return [];
35
+ const matches = [];
36
+ const cursor = query.getCursor(doc);
37
+ for (let next = cursor.next(); !next.done; next = cursor.next()) {
38
+ matches.push({ from: next.value.from, to: next.value.to });
39
+ }
40
+ return matches;
41
+ }
42
+ /** Replacement text for one match, including regular-expression substitutions. */
43
+ export function searchReplacement(query, matched) {
44
+ const replacement = query.literal
45
+ ? query.replace
46
+ : query.replace.replace(/\\([nrt\\])/g, (_match, escape) => escape === "n"
47
+ ? "\n"
48
+ : escape === "r"
49
+ ? "\r"
50
+ : escape === "t"
51
+ ? "\t"
52
+ : "\\");
53
+ if (!query.regexp)
54
+ return replacement;
55
+ const flags = query.caseSensitive ? "" : "i";
56
+ return matched.replace(new RegExp(query.search, flags), replacement);
57
+ }
58
+ export function replaceCellText(cell, ranges, query) {
59
+ const ordered = [...ranges].sort((left, right) => right.from - left.from);
60
+ let next = cell;
61
+ for (const range of ordered) {
62
+ const matched = next.slice(range.from, range.to);
63
+ next =
64
+ next.slice(0, range.from) +
65
+ searchReplacement(query, matched) +
66
+ next.slice(range.to);
67
+ }
68
+ return next;
69
+ }
70
+ export function csvBodyCounts(rowCount, colCount, headerRow) {
71
+ return {
72
+ columns: colCount,
73
+ rows: headerRow ? Math.max(0, rowCount - 1) : rowCount,
74
+ };
75
+ }
76
+ /** Data rows that contain a match. Header matches do not count. */
77
+ export function csvShownRowCount(rowCount, headerRow, matches) {
78
+ const start = headerRow ? 1 : 0;
79
+ const matched = new Set();
80
+ for (const match of matches) {
81
+ if (match.row >= start && match.row < rowCount)
82
+ matched.add(match.row);
83
+ }
84
+ return matched.size;
85
+ }
86
+ export function csvStatusLabel(columns, rows, shownRows) {
87
+ const columnLabel = columns === 1 ? "column" : "columns";
88
+ const rowLabel = rows === 1 ? "row" : "rows";
89
+ const counts = `${columns.toLocaleString()} ${columnLabel}`;
90
+ if (shownRows == null) {
91
+ return `${counts} · ${rows.toLocaleString()} ${rowLabel}`;
92
+ }
93
+ const shownLabel = shownRows === 1 ? "row" : "rows";
94
+ return `${counts} · Showing ${shownRows.toLocaleString()} ${shownLabel} (filtered from ${rows.toLocaleString()} total ${rowLabel})`;
95
+ }
96
+ export function isCsvFindShortcut(event) {
97
+ return ((event.metaKey || event.ctrlKey) &&
98
+ !event.altKey &&
99
+ !event.shiftKey &&
100
+ event.key.toLowerCase() === "f");
101
+ }
@@ -0,0 +1,10 @@
1
+ import type { CsvGrid } from "./csv-grid";
2
+ export type CsvTableRow = {
3
+ id: string;
4
+ rowIndex: number;
5
+ /** 1-based visible row index in the table body (independent of grid row). */
6
+ displayRowNumber: number;
7
+ cells: string[];
8
+ };
9
+ export declare function rowsFromGrid(grid: CsvGrid, headerRow: boolean): CsvTableRow[];
10
+ export declare function headerLabelsFromGrid(grid: CsvGrid, headerRow: boolean, colCount: number): string[];
@@ -0,0 +1,18 @@
1
+ export function rowsFromGrid(grid, headerRow) {
2
+ const all = grid.getRows();
3
+ const offset = headerRow ? 1 : 0;
4
+ return all.slice(offset).map((cells, index) => ({
5
+ id: `row-${offset + index}`,
6
+ rowIndex: offset + index,
7
+ displayRowNumber: index + 1,
8
+ cells: [...cells],
9
+ }));
10
+ }
11
+ export function headerLabelsFromGrid(grid, headerRow, colCount) {
12
+ return Array.from({ length: colCount }, (_, column) => {
13
+ if (headerRow && grid.getRowCount() > 0) {
14
+ return grid.getCell(0, column);
15
+ }
16
+ return `Column ${column + 1}`;
17
+ });
18
+ }
@@ -0,0 +1,10 @@
1
+ import Papa from "papaparse";
2
+ import type { CsvDelimiter } from "../../csv-settings";
3
+ export type ParseCsvOptions = {
4
+ delimiter: CsvDelimiter;
5
+ };
6
+ export type ParseCsvResult = {
7
+ rows: string[][];
8
+ errors: Papa.ParseError[];
9
+ };
10
+ export declare function parseCsvText(text: string, options: ParseCsvOptions): ParseCsvResult;
@@ -0,0 +1,13 @@
1
+ import Papa from "papaparse";
2
+ export function parseCsvText(text, options) {
3
+ const trimmed = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
4
+ const parsed = Papa.parse(trimmed, {
5
+ delimiter: options.delimiter,
6
+ skipEmptyLines: false,
7
+ });
8
+ const rows = parsed.data.map((row) => row.map((cell) => (cell ?? "").toString()));
9
+ return {
10
+ rows,
11
+ errors: parsed.errors ?? [],
12
+ };
13
+ }
@@ -0,0 +1,5 @@
1
+ import type { CsvDelimiter } from "../../csv-settings";
2
+ export type SerializeCsvOptions = {
3
+ delimiter: CsvDelimiter;
4
+ };
5
+ export declare function serializeCsvRows(rows: string[][], options: SerializeCsvOptions): string;
@@ -0,0 +1,10 @@
1
+ import Papa from "papaparse";
2
+ export function serializeCsvRows(rows, options) {
3
+ return Papa.unparse(rows, {
4
+ delimiter: options.delimiter,
5
+ newline: "\n",
6
+ quotes: true,
7
+ quoteChar: '"',
8
+ escapeChar: '"',
9
+ });
10
+ }
@@ -0,0 +1,244 @@
1
+ <script lang="ts">
2
+ import { Button } from "@lapismd/design-core/shadcn/button";
3
+ import { Toggle } from "@lapismd/design-core/shadcn/toggle";
4
+ import * as Tooltip from "@lapismd/design-core/shadcn/tooltip";
5
+ import SheetGlyph from "./sheet-glyph.svelte";
6
+ import type { SheetCommand, SheetCommandId } from "./sheet-layout";
7
+
8
+ let {
9
+ reference,
10
+ commands,
11
+ wrap,
12
+ colours,
13
+ headerRow,
14
+ canUndo,
15
+ canRedo,
16
+ onAddress,
17
+ onCommand,
18
+ onWrap,
19
+ onColours,
20
+ onHeaderRow,
21
+ onUndo,
22
+ onRedo,
23
+ }: {
24
+ reference: string;
25
+ commands: readonly SheetCommand[];
26
+ wrap: boolean;
27
+ colours: boolean;
28
+ headerRow: boolean;
29
+ canUndo: boolean;
30
+ canRedo: boolean;
31
+ onAddress: (address: string) => void;
32
+ onCommand: (id: SheetCommandId) => void;
33
+ onWrap: (wrap: boolean) => void;
34
+ onColours: (colours: boolean) => void;
35
+ onHeaderRow: (headerRow: boolean) => void;
36
+ onUndo: () => void;
37
+ onRedo: () => void;
38
+ } = $props();
39
+
40
+ let draft = $state<string | null>(null);
41
+
42
+ function commitAddress() {
43
+ if (draft == null) return;
44
+ const value = draft;
45
+ draft = null;
46
+ onAddress(value);
47
+ }
48
+ </script>
49
+
50
+ <div class="csv-sheet-toolbar" role="toolbar" aria-label="Sheet" data-sheet-toolbar>
51
+ <input
52
+ class="csv-sheet-toolbar__name"
53
+ data-sheet-reference
54
+ aria-label="Cell address"
55
+ value={draft ?? reference}
56
+ spellcheck="false"
57
+ onfocus={(event) => event.currentTarget.select()}
58
+ oninput={(event) => {
59
+ draft = event.currentTarget.value;
60
+ }}
61
+ onkeydown={(event) => {
62
+ if (event.key === "Enter") {
63
+ event.preventDefault();
64
+ commitAddress();
65
+ event.currentTarget.blur();
66
+ } else if (event.key === "Escape") {
67
+ draft = null;
68
+ event.currentTarget.blur();
69
+ }
70
+ }}
71
+ onblur={commitAddress}
72
+ />
73
+ <Tooltip.Provider delayDuration={300}>
74
+ <Tooltip.Root>
75
+ <Tooltip.Trigger>
76
+ {#snippet child({ props })}
77
+ <Button
78
+ {...props}
79
+ variant="ghost"
80
+ size="icon-sm"
81
+ aria-label="Undo"
82
+ data-sheet-undo
83
+ disabled={!canUndo}
84
+ onclick={onUndo}
85
+ >
86
+ <SheetGlyph command="undo" />
87
+ </Button>
88
+ {/snippet}
89
+ </Tooltip.Trigger>
90
+ <Tooltip.Content side="bottom">Undo</Tooltip.Content>
91
+ </Tooltip.Root>
92
+ <Tooltip.Root>
93
+ <Tooltip.Trigger>
94
+ {#snippet child({ props })}
95
+ <Button
96
+ {...props}
97
+ variant="ghost"
98
+ size="icon-sm"
99
+ aria-label="Redo"
100
+ data-sheet-redo
101
+ disabled={!canRedo}
102
+ onclick={onRedo}
103
+ >
104
+ <SheetGlyph command="redo" />
105
+ </Button>
106
+ {/snippet}
107
+ </Tooltip.Trigger>
108
+ <Tooltip.Content side="bottom">Redo</Tooltip.Content>
109
+ </Tooltip.Root>
110
+ {#each commands as command (command.id)}
111
+ <Tooltip.Root>
112
+ <Tooltip.Trigger>
113
+ {#snippet child({ props })}
114
+ <Button
115
+ {...props}
116
+ variant="ghost"
117
+ size="icon-sm"
118
+ aria-label={command.label}
119
+ disabled={command.disabled}
120
+ onclick={() => onCommand(command.id)}
121
+ >
122
+ <SheetGlyph command={command.id} />
123
+ </Button>
124
+ {/snippet}
125
+ </Tooltip.Trigger>
126
+ <Tooltip.Content side="bottom">{command.label}</Tooltip.Content>
127
+ </Tooltip.Root>
128
+ {/each}
129
+ <span class="csv-sheet-toolbar__rule" aria-hidden="true"></span>
130
+ <Tooltip.Root>
131
+ <Tooltip.Trigger>
132
+ {#snippet child({ props })}
133
+ <Toggle
134
+ {...props}
135
+ pressed={wrap}
136
+ size="sm"
137
+ variant="outline"
138
+ aria-label="Wrap text"
139
+ aria-pressed={wrap}
140
+ data-sheet-wrap
141
+ onPressedChange={(pressed) => onWrap(pressed === true)}
142
+ >
143
+ <SheetGlyph command="wrap" />
144
+ </Toggle>
145
+ {/snippet}
146
+ </Tooltip.Trigger>
147
+ <Tooltip.Content side="bottom">Wrap text</Tooltip.Content>
148
+ </Tooltip.Root>
149
+ <Tooltip.Root>
150
+ <Tooltip.Trigger>
151
+ {#snippet child({ props })}
152
+ <Toggle
153
+ {...props}
154
+ pressed={colours}
155
+ size="sm"
156
+ variant="outline"
157
+ aria-label="Column colours"
158
+ aria-pressed={colours}
159
+ data-sheet-colours
160
+ onPressedChange={(pressed) => onColours(pressed === true)}
161
+ >
162
+ <SheetGlyph command="colours" />
163
+ </Toggle>
164
+ {/snippet}
165
+ </Tooltip.Trigger>
166
+ <Tooltip.Content side="bottom">Column colours</Tooltip.Content>
167
+ </Tooltip.Root>
168
+ <Tooltip.Root>
169
+ <Tooltip.Trigger>
170
+ {#snippet child({ props })}
171
+ <Toggle
172
+ {...props}
173
+ pressed={headerRow}
174
+ size="sm"
175
+ variant="outline"
176
+ aria-label="Header row"
177
+ aria-pressed={headerRow}
178
+ data-sheet-header
179
+ onPressedChange={(pressed) => onHeaderRow(pressed === true)}
180
+ >
181
+ <SheetGlyph command="header" />
182
+ </Toggle>
183
+ {/snippet}
184
+ </Tooltip.Trigger>
185
+ <Tooltip.Content side="bottom">Header row</Tooltip.Content>
186
+ </Tooltip.Root>
187
+ </Tooltip.Provider>
188
+ </div>
189
+
190
+ <style>
191
+ .csv-sheet-toolbar {
192
+ display: flex;
193
+ flex: none;
194
+ align-items: center;
195
+ gap: 0.25rem;
196
+ min-height: 2.25rem;
197
+ padding: 0.25rem 0.5rem;
198
+ border-bottom: 1px solid var(--csv-surface-border, var(--border));
199
+ background: var(--csv-header-background, var(--background));
200
+ color: var(--csv-text-color, var(--foreground));
201
+ font-family: var(--font-interface, var(--font-sans, ui-sans-serif, system-ui, sans-serif));
202
+ font-size: 13px;
203
+ }
204
+
205
+ .csv-sheet-toolbar__name {
206
+ display: inline-flex;
207
+ align-items: center;
208
+ justify-content: center;
209
+ width: 4.5rem;
210
+ height: 1.75rem;
211
+ margin-right: 0.25rem;
212
+ padding: 0 0.5rem;
213
+ border: 1px solid var(--csv-surface-border, var(--border));
214
+ border-radius: 0.25rem;
215
+ background: var(--csv-shell-background, var(--background));
216
+ color: inherit;
217
+ font: inherit;
218
+ font-variant-numeric: tabular-nums;
219
+ text-align: center;
220
+ }
221
+
222
+ .csv-sheet-toolbar__name:focus {
223
+ outline: 2px solid var(--table-selection-border-color, var(--interactive-accent, var(--accent)));
224
+ outline-offset: 1px;
225
+ }
226
+
227
+ .csv-sheet-toolbar :global(button:hover:not(:disabled)) {
228
+ background: color-mix(in srgb, var(--foreground) 10%, transparent);
229
+ }
230
+
231
+ .csv-sheet-toolbar :global(button[aria-pressed="true"]),
232
+ .csv-sheet-toolbar :global(button[aria-pressed="true"]:hover) {
233
+ background: var(--table-selection-border-color, var(--interactive-accent, var(--accent)));
234
+ color: var(--csv-shell-background, #fff);
235
+ border-color: transparent;
236
+ }
237
+
238
+ .csv-sheet-toolbar__rule {
239
+ width: 1px;
240
+ height: 1.25rem;
241
+ margin: 0 0.25rem;
242
+ background: var(--csv-surface-border, var(--border));
243
+ }
244
+ </style>
@@ -0,0 +1,20 @@
1
+ import type { SheetCommand, SheetCommandId } from "./sheet-layout";
2
+ type $$ComponentProps = {
3
+ reference: string;
4
+ commands: readonly SheetCommand[];
5
+ wrap: boolean;
6
+ colours: boolean;
7
+ headerRow: boolean;
8
+ canUndo: boolean;
9
+ canRedo: boolean;
10
+ onAddress: (address: string) => void;
11
+ onCommand: (id: SheetCommandId) => void;
12
+ onWrap: (wrap: boolean) => void;
13
+ onColours: (colours: boolean) => void;
14
+ onHeaderRow: (headerRow: boolean) => void;
15
+ onUndo: () => void;
16
+ onRedo: () => void;
17
+ };
18
+ declare const CsvSheetToolbar: import("svelte").Component<$$ComponentProps, {}, "">;
19
+ type CsvSheetToolbar = ReturnType<typeof CsvSheetToolbar>;
20
+ export default CsvSheetToolbar;