@lapis-notes/csv 0.0.0-stage → 0.2.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/CHANGELOG.md +28 -0
- package/LICENSE.md +4 -0
- package/README.md +19 -2
- package/dist/app.css +210 -0
- package/dist/csv-settings.d.ts +13 -0
- package/dist/csv-settings.js +28 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/lib/CsvSheet.svelte +58 -0
- package/dist/lib/CsvSheet.svelte.d.ts +11 -0
- package/dist/lib/CsvTable.svelte +58 -0
- package/dist/lib/CsvTable.svelte.d.ts +11 -0
- package/dist/lib/codemirror/csv-language-extensions.d.ts +3 -0
- package/dist/lib/codemirror/csv-language-extensions.js +11 -0
- package/dist/lib/codemirror/csv-language.d.ts +3 -0
- package/dist/lib/codemirror/csv-language.js +24 -0
- package/dist/lib/codemirror/csv-rainbow-theme.d.ts +3 -0
- package/dist/lib/codemirror/csv-rainbow-theme.js +15 -0
- package/dist/lib/codemirror/csv-source-extensions.d.ts +7 -0
- package/dist/lib/codemirror/csv-source-extensions.js +9 -0
- package/dist/lib/codemirror/csv.parser.d.ts +2 -0
- package/dist/lib/codemirror/csv.parser.js +16 -0
- package/dist/lib/codemirror/csv.parser.terms.d.ts +1 -0
- package/dist/lib/codemirror/csv.parser.terms.js +2 -0
- package/dist/lib/codemirror/syntax.grammar +36 -0
- package/dist/lib/components/csv-cell.svelte +137 -0
- package/dist/lib/components/csv-cell.svelte.d.ts +11 -0
- package/dist/lib/components/csv-data-table-column-head.svelte +76 -0
- package/dist/lib/components/csv-data-table-column-head.svelte.d.ts +17 -0
- package/dist/lib/components/csv-data-table-column-header.svelte +159 -0
- package/dist/lib/components/csv-data-table-column-header.svelte.d.ts +23 -0
- package/dist/lib/components/csv-data-table-data-cell.svelte +72 -0
- package/dist/lib/components/csv-data-table-data-cell.svelte.d.ts +18 -0
- package/dist/lib/components/csv-data-table-drag-overlay.svelte +119 -0
- package/dist/lib/components/csv-data-table-drag-overlay.svelte.d.ts +13 -0
- package/dist/lib/components/csv-data-table-row-actions.svelte +47 -0
- package/dist/lib/components/csv-data-table-row-actions.svelte.d.ts +8 -0
- package/dist/lib/components/csv-data-table-row-grip-cell.svelte +102 -0
- package/dist/lib/components/csv-data-table-row-grip-cell.svelte.d.ts +19 -0
- package/dist/lib/components/csv-data-table-row.svelte +38 -0
- package/dist/lib/components/csv-data-table-row.svelte.d.ts +11 -0
- package/dist/lib/components/csv-data-table.svelte +903 -0
- package/dist/lib/components/csv-data-table.svelte.d.ts +21 -0
- package/dist/lib/components/csv-find.svelte +382 -0
- package/dist/lib/components/csv-find.svelte.d.ts +24 -0
- package/dist/lib/components/csv-row-virtualizer.svelte.d.ts +9 -0
- package/dist/lib/components/csv-row-virtualizer.svelte.js +59 -0
- package/dist/lib/components/csv-source-view.svelte +127 -0
- package/dist/lib/components/csv-source-view.svelte.d.ts +10 -0
- package/dist/lib/components/csv-status-bar.svelte +101 -0
- package/dist/lib/components/csv-status-bar.svelte.d.ts +14 -0
- package/dist/lib/components/csv-table-dnd.d.ts +9 -0
- package/dist/lib/components/csv-table-dnd.js +12 -0
- package/dist/lib/components/csv-table-drag-measure.d.ts +7 -0
- package/dist/lib/components/csv-table-drag-measure.js +38 -0
- package/dist/lib/components/csv-table-selection.d.ts +28 -0
- package/dist/lib/components/csv-table-selection.js +178 -0
- package/dist/lib/components/csv-table-view.svelte +265 -0
- package/dist/lib/components/csv-table-view.svelte.d.ts +16 -0
- package/dist/lib/csv-plugin.d.ts +9 -0
- package/dist/lib/csv-plugin.js +107 -0
- package/dist/lib/csv-view-settings.d.ts +43 -0
- package/dist/lib/csv-view-settings.js +86 -0
- package/dist/lib/ids.d.ts +8 -0
- package/dist/lib/ids.js +19 -0
- package/dist/lib/model/csv-column-sort.d.ts +16 -0
- package/dist/lib/model/csv-column-sort.js +81 -0
- package/dist/lib/model/csv-grid.d.ts +31 -0
- package/dist/lib/model/csv-grid.js +161 -0
- package/dist/lib/model/csv-search.d.ts +38 -0
- package/dist/lib/model/csv-search.js +101 -0
- package/dist/lib/model/csv-table-model.d.ts +10 -0
- package/dist/lib/model/csv-table-model.js +18 -0
- package/dist/lib/model/parse-csv.d.ts +10 -0
- package/dist/lib/model/parse-csv.js +13 -0
- package/dist/lib/model/serialize-csv.d.ts +5 -0
- package/dist/lib/model/serialize-csv.js +10 -0
- package/dist/lib/sheet/csv-sheet-toolbar.svelte +244 -0
- package/dist/lib/sheet/csv-sheet-toolbar.svelte.d.ts +20 -0
- package/dist/lib/sheet/csv-sheet-view.svelte +444 -0
- package/dist/lib/sheet/csv-sheet-view.svelte.d.ts +18 -0
- package/dist/lib/sheet/csv-sheet.svelte +1121 -0
- package/dist/lib/sheet/csv-sheet.svelte.d.ts +37 -0
- package/dist/lib/sheet/sheet-glyph.svelte +57 -0
- package/dist/lib/sheet/sheet-glyph.svelte.d.ts +7 -0
- package/dist/lib/sheet/sheet-history.d.ts +14 -0
- package/dist/lib/sheet/sheet-history.js +33 -0
- package/dist/lib/sheet/sheet-layout.d.ts +121 -0
- package/dist/lib/sheet/sheet-layout.js +336 -0
- package/dist/lib/sheet/sheet-paint.d.ts +45 -0
- package/dist/lib/sheet/sheet-paint.js +274 -0
- package/dist/lib/sheet/sheet-theme.d.ts +2 -0
- package/dist/lib/sheet/sheet-theme.js +26 -0
- package/dist/lib/views/csv-view-mode.d.ts +3 -0
- package/dist/lib/views/csv-view-mode.js +6 -0
- package/dist/lib/views/csv-view.d.ts +24 -0
- package/dist/lib/views/csv-view.js +125 -0
- package/dist/styles/csv-find.css +313 -0
- package/dist/styles/csv-table.css +882 -0
- package/dist/styles.css +37 -0
- package/manifest.json +45 -0
- package/package.json +86 -3
- package/registry-content/overview.md +3 -0
- package/registry.json +322 -0
- package/styles.css +1 -0
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from "@lapis-notes/ui";
|
|
3
|
+
import type { App, TFile } from "@lapis-notes/api";
|
|
4
|
+
import { onMount } from "svelte";
|
|
5
|
+
import type { Attachment } from "svelte/attachments";
|
|
6
|
+
import {
|
|
7
|
+
noteCsvColumnDeleted,
|
|
8
|
+
noteCsvColumnMoved,
|
|
9
|
+
noteCsvColumnSortEdit,
|
|
10
|
+
toggleCsvColumnSort,
|
|
11
|
+
type CsvColumnSort,
|
|
12
|
+
} from "../model/csv-column-sort";
|
|
13
|
+
import {
|
|
14
|
+
emptySheetHistory,
|
|
15
|
+
recordSheetEdit,
|
|
16
|
+
redoSheetEdit,
|
|
17
|
+
undoSheetEdit,
|
|
18
|
+
} from "./sheet-history";
|
|
19
|
+
import { CsvGrid } from "../model/csv-grid";
|
|
20
|
+
import { parseCsvText } from "../model/parse-csv";
|
|
21
|
+
import {
|
|
22
|
+
csvBodyCounts,
|
|
23
|
+
csvCellMatches,
|
|
24
|
+
csvSearchQuery,
|
|
25
|
+
csvShownRowCount,
|
|
26
|
+
isCsvFindShortcut,
|
|
27
|
+
} from "../model/csv-search";
|
|
28
|
+
import {
|
|
29
|
+
resolveDelimiter,
|
|
30
|
+
type CsvPluginSettings,
|
|
31
|
+
} from "../../csv-settings";
|
|
32
|
+
import CsvFind from "../components/csv-find.svelte";
|
|
33
|
+
import CsvStatusBar from "../components/csv-status-bar.svelte";
|
|
34
|
+
import CsvSheet from "./csv-sheet.svelte";
|
|
35
|
+
import {
|
|
36
|
+
SHEET_DEFAULT_COLUMN_WIDTH,
|
|
37
|
+
readSessionWidths,
|
|
38
|
+
writeSessionWidths,
|
|
39
|
+
} from "./sheet-layout";
|
|
40
|
+
|
|
41
|
+
let {
|
|
42
|
+
app,
|
|
43
|
+
file,
|
|
44
|
+
content,
|
|
45
|
+
settings,
|
|
46
|
+
class: className,
|
|
47
|
+
onContentChange,
|
|
48
|
+
onShowTable,
|
|
49
|
+
onToggleSource,
|
|
50
|
+
onSettingsChange,
|
|
51
|
+
}: {
|
|
52
|
+
app: App;
|
|
53
|
+
file: TFile;
|
|
54
|
+
content: string;
|
|
55
|
+
settings: CsvPluginSettings;
|
|
56
|
+
class?: string;
|
|
57
|
+
onContentChange?: (text: string) => void;
|
|
58
|
+
onShowTable?: () => void;
|
|
59
|
+
onToggleSource?: () => void;
|
|
60
|
+
onSettingsChange?: (patch: { headerRow?: boolean }) => void;
|
|
61
|
+
} = $props();
|
|
62
|
+
|
|
63
|
+
let incoming = $state<string | null>(null);
|
|
64
|
+
let searchOpen = $state(false);
|
|
65
|
+
let searchRequest = $state(0);
|
|
66
|
+
let searchValue = $state("");
|
|
67
|
+
let replaceValue = $state("");
|
|
68
|
+
let caseSensitive = $state(false);
|
|
69
|
+
let wholeWord = $state(false);
|
|
70
|
+
let regexp = $state(false);
|
|
71
|
+
let active = $state(0);
|
|
72
|
+
let columnSort = $state<CsvColumnSort | null>(null);
|
|
73
|
+
let widthOverride = $state<{ path: string; widths: number[] } | null>(null);
|
|
74
|
+
let history = $state(emptySheetHistory<SheetSnapshot>());
|
|
75
|
+
|
|
76
|
+
type SheetSnapshot = {
|
|
77
|
+
text: string;
|
|
78
|
+
widths: number[];
|
|
79
|
+
sort: CsvColumnSort | null;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const text = $derived(incoming ?? content);
|
|
83
|
+
const delimiter = $derived(resolveDelimiter(settings, file.extension));
|
|
84
|
+
const parsed = $derived.by(() => {
|
|
85
|
+
const source = text;
|
|
86
|
+
const result = parseCsvText(source, { delimiter });
|
|
87
|
+
return {
|
|
88
|
+
errors: result.errors.map(
|
|
89
|
+
(error) => `Row ${error.row ?? "?"}: ${error.message}`,
|
|
90
|
+
),
|
|
91
|
+
grid:
|
|
92
|
+
result.rows.length > 0
|
|
93
|
+
? CsvGrid.fromText(source, {
|
|
94
|
+
delimiter,
|
|
95
|
+
headerRow: settings.headerRow,
|
|
96
|
+
})
|
|
97
|
+
: CsvGrid.empty(),
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
const rows = $derived(parsed.grid.getRows());
|
|
101
|
+
const counts = $derived(
|
|
102
|
+
csvBodyCounts(
|
|
103
|
+
parsed.grid.getRowCount(),
|
|
104
|
+
parsed.grid.getColCount(),
|
|
105
|
+
settings.headerRow,
|
|
106
|
+
),
|
|
107
|
+
);
|
|
108
|
+
const searchQuery = $derived(
|
|
109
|
+
csvSearchQuery({
|
|
110
|
+
search: searchValue,
|
|
111
|
+
replace: replaceValue,
|
|
112
|
+
caseSensitive,
|
|
113
|
+
wholeWord,
|
|
114
|
+
regexp,
|
|
115
|
+
}),
|
|
116
|
+
);
|
|
117
|
+
const filtering = $derived(
|
|
118
|
+
searchOpen && searchQuery.search.length > 0 && searchQuery.valid,
|
|
119
|
+
);
|
|
120
|
+
const searchMatches = $derived.by(() => {
|
|
121
|
+
if (!filtering) return [];
|
|
122
|
+
return csvCellMatches(rows, searchQuery);
|
|
123
|
+
});
|
|
124
|
+
const matchedRows = $derived(
|
|
125
|
+
new Set(searchMatches.map((match) => match.row)),
|
|
126
|
+
);
|
|
127
|
+
const bodyRows = $derived.by(() => {
|
|
128
|
+
const start = settings.headerRow ? 1 : 0;
|
|
129
|
+
const indexes: number[] = [];
|
|
130
|
+
for (let index = start; index < rows.length; index += 1) {
|
|
131
|
+
if (!filtering || matchedRows.has(index)) indexes.push(index);
|
|
132
|
+
}
|
|
133
|
+
return indexes;
|
|
134
|
+
});
|
|
135
|
+
const shownRows = $derived(
|
|
136
|
+
filtering
|
|
137
|
+
? csvShownRowCount(rows.length, settings.headerRow, searchMatches)
|
|
138
|
+
: undefined,
|
|
139
|
+
);
|
|
140
|
+
const searchCell = $derived.by(() => {
|
|
141
|
+
if (searchMatches.length === 0) return null;
|
|
142
|
+
const match = searchMatches[Math.min(active, searchMatches.length - 1)];
|
|
143
|
+
return match ? { row: match.row, col: match.col } : null;
|
|
144
|
+
});
|
|
145
|
+
const widths = $derived.by(() => {
|
|
146
|
+
const count = parsed.grid.getColCount();
|
|
147
|
+
const stored = widthOverride;
|
|
148
|
+
if (
|
|
149
|
+
stored &&
|
|
150
|
+
stored.path === file.path &&
|
|
151
|
+
stored.widths.length === count
|
|
152
|
+
) {
|
|
153
|
+
return stored.widths;
|
|
154
|
+
}
|
|
155
|
+
return readSessionWidths(file.path, count);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
function copySort(sort: CsvColumnSort | null): CsvColumnSort | null {
|
|
159
|
+
if (!sort) return null;
|
|
160
|
+
return {
|
|
161
|
+
index: sort.index,
|
|
162
|
+
direction: sort.direction,
|
|
163
|
+
baseline: sort.baseline.map((row) => [...row]),
|
|
164
|
+
order: [...sort.order],
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function snapshot(): SheetSnapshot {
|
|
169
|
+
return { text, widths: [...widths], sort: copySort(columnSort) };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function publish(nextGrid: CsvGrid, before: SheetSnapshot) {
|
|
173
|
+
const next = nextGrid.toText({ delimiter });
|
|
174
|
+
if (before.text !== next) history = recordSheetEdit(history, before);
|
|
175
|
+
incoming = next;
|
|
176
|
+
onContentChange?.(next);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function restore(entry: SheetSnapshot) {
|
|
180
|
+
incoming = entry.text;
|
|
181
|
+
columnSort = copySort(entry.sort);
|
|
182
|
+
rememberWidths([...entry.widths]);
|
|
183
|
+
onContentChange?.(entry.text);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function undoSheet() {
|
|
187
|
+
const step = undoSheetEdit(history, snapshot());
|
|
188
|
+
if (!step) return;
|
|
189
|
+
history = step.history;
|
|
190
|
+
restore(step.value);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function redoSheet() {
|
|
194
|
+
const step = redoSheetEdit(history, snapshot());
|
|
195
|
+
if (!step) return;
|
|
196
|
+
history = step.history;
|
|
197
|
+
restore(step.value);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function rememberWidths(next: number[]) {
|
|
201
|
+
widthOverride = { path: file.path, widths: next };
|
|
202
|
+
writeSessionWidths(file.path, next);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function changeCell(row: number, col: number, value: string) {
|
|
206
|
+
const before = snapshot();
|
|
207
|
+
const next = parsed.grid.clone();
|
|
208
|
+
next.updateCell(row, col, value);
|
|
209
|
+
if (columnSort) noteCsvColumnSortEdit(columnSort, row, col, value);
|
|
210
|
+
publish(next, before);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function sortColumn(col: number) {
|
|
214
|
+
const before = snapshot();
|
|
215
|
+
const next = parsed.grid.clone();
|
|
216
|
+
columnSort = toggleCsvColumnSort(
|
|
217
|
+
next,
|
|
218
|
+
columnSort,
|
|
219
|
+
col,
|
|
220
|
+
settings.headerRow,
|
|
221
|
+
);
|
|
222
|
+
publish(next, before);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function deleteRow(index: number) {
|
|
226
|
+
const before = snapshot();
|
|
227
|
+
const next = parsed.grid.clone();
|
|
228
|
+
next.deleteRowAt(index);
|
|
229
|
+
columnSort = null;
|
|
230
|
+
publish(next, before);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function deleteColumn(index: number) {
|
|
234
|
+
const before = snapshot();
|
|
235
|
+
const next = parsed.grid.clone();
|
|
236
|
+
next.deleteColumnAt(index);
|
|
237
|
+
columnSort = noteCsvColumnDeleted(columnSort, index);
|
|
238
|
+
const stored = widths.filter((_, column) => column !== index);
|
|
239
|
+
rememberWidths(stored.length > 0 ? stored : [SHEET_DEFAULT_COLUMN_WIDTH]);
|
|
240
|
+
publish(next, before);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function moveColumn(from: number, to: number) {
|
|
244
|
+
if (from === to || to < 0 || to >= parsed.grid.getColCount()) return;
|
|
245
|
+
const before = snapshot();
|
|
246
|
+
const next = parsed.grid.clone();
|
|
247
|
+
next.moveColumnAt(from, to);
|
|
248
|
+
columnSort = noteCsvColumnMoved(columnSort, from, to);
|
|
249
|
+
const stored = [...widths];
|
|
250
|
+
const [width] = stored.splice(from, 1);
|
|
251
|
+
stored.splice(to, 0, width ?? SHEET_DEFAULT_COLUMN_WIDTH);
|
|
252
|
+
rememberWidths(stored);
|
|
253
|
+
publish(next, before);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function moveRow(from: number, to: number) {
|
|
257
|
+
if (from === to || to < 0 || to >= parsed.grid.getRowCount()) return;
|
|
258
|
+
const before = snapshot();
|
|
259
|
+
const next = parsed.grid.clone();
|
|
260
|
+
next.moveRowAt(from, to);
|
|
261
|
+
columnSort = null;
|
|
262
|
+
publish(next, before);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function clearCoordinates(coords: Array<[number, number]>) {
|
|
266
|
+
const before = snapshot();
|
|
267
|
+
const next = parsed.grid.clone();
|
|
268
|
+
next.clearCellsAt(coords);
|
|
269
|
+
if (columnSort) {
|
|
270
|
+
for (const [row, col] of coords) {
|
|
271
|
+
noteCsvColumnSortEdit(columnSort, row, col, "");
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
publish(next, before);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function clearColumn(col: number) {
|
|
278
|
+
const coords: Array<[number, number]> = [];
|
|
279
|
+
for (let row = 0; row < parsed.grid.getRowCount(); row += 1) {
|
|
280
|
+
coords.push([row, col]);
|
|
281
|
+
}
|
|
282
|
+
clearCoordinates(coords);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function clearRow(row: number) {
|
|
286
|
+
const coords: Array<[number, number]> = [];
|
|
287
|
+
for (let col = 0; col < parsed.grid.getColCount(); col += 1) {
|
|
288
|
+
coords.push([row, col]);
|
|
289
|
+
}
|
|
290
|
+
clearCoordinates(coords);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function clearCell(row: number, col: number) {
|
|
294
|
+
changeCell(row, col, "");
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function clearSheet() {
|
|
298
|
+
const coords: Array<[number, number]> = [];
|
|
299
|
+
for (let row = 0; row < parsed.grid.getRowCount(); row += 1) {
|
|
300
|
+
for (let col = 0; col < parsed.grid.getColCount(); col += 1) {
|
|
301
|
+
coords.push([row, col]);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
clearCoordinates(coords);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function deleteSheet() {
|
|
308
|
+
const before = snapshot();
|
|
309
|
+
const next = parsed.grid.clone();
|
|
310
|
+
while (next.getRowCount() > 1) next.deleteRowAt(next.getRowCount() - 1);
|
|
311
|
+
if (!settings.headerRow) {
|
|
312
|
+
const coords: Array<[number, number]> = [];
|
|
313
|
+
for (let col = 0; col < next.getColCount(); col += 1) coords.push([0, col]);
|
|
314
|
+
next.clearCellsAt(coords);
|
|
315
|
+
}
|
|
316
|
+
columnSort = null;
|
|
317
|
+
publish(next, before);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function replaceCells(edits: { row: number; col: number; value: string }[]) {
|
|
321
|
+
const before = snapshot();
|
|
322
|
+
const next = parsed.grid.clone();
|
|
323
|
+
for (const edit of edits) {
|
|
324
|
+
next.updateCell(edit.row, edit.col, edit.value);
|
|
325
|
+
if (columnSort) noteCsvColumnSortEdit(columnSort, edit.row, edit.col, edit.value);
|
|
326
|
+
}
|
|
327
|
+
publish(next, before);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function openSearch() {
|
|
331
|
+
searchOpen = true;
|
|
332
|
+
searchRequest += 1;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function toggleSearch() {
|
|
336
|
+
if (searchOpen) {
|
|
337
|
+
searchOpen = false;
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
openSearch();
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function onFindShortcut(event: KeyboardEvent) {
|
|
344
|
+
if (!isCsvFindShortcut(event)) return;
|
|
345
|
+
event.preventDefault();
|
|
346
|
+
event.stopPropagation();
|
|
347
|
+
openSearch();
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function onHistoryShortcut(event: KeyboardEvent) {
|
|
351
|
+
const target = event.target;
|
|
352
|
+
if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) return;
|
|
353
|
+
const meta = event.metaKey || event.ctrlKey;
|
|
354
|
+
if (!meta || event.altKey) return;
|
|
355
|
+
const key = event.key.toLowerCase();
|
|
356
|
+
if (key === "z" && !event.shiftKey) {
|
|
357
|
+
event.preventDefault();
|
|
358
|
+
undoSheet();
|
|
359
|
+
} else if ((key === "z" && event.shiftKey) || key === "y") {
|
|
360
|
+
event.preventDefault();
|
|
361
|
+
redoSheet();
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const findShortcut: Attachment<HTMLElement> = (node) => {
|
|
366
|
+
node.addEventListener("keydown", onFindShortcut, true);
|
|
367
|
+
node.addEventListener("keydown", onHistoryShortcut);
|
|
368
|
+
return () => {
|
|
369
|
+
node.removeEventListener("keydown", onFindShortcut, true);
|
|
370
|
+
node.removeEventListener("keydown", onHistoryShortcut);
|
|
371
|
+
};
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
onMount(() => {
|
|
375
|
+
const currentApp = app;
|
|
376
|
+
const currentFile = file;
|
|
377
|
+
const modified = currentApp.vault.on("modify", (candidate) => {
|
|
378
|
+
if (candidate.path !== currentFile.path) return;
|
|
379
|
+
void currentApp.vault.cachedRead(currentFile).then((next) => {
|
|
380
|
+
incoming = next;
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
return () => {
|
|
384
|
+
currentApp.vault.offref(modified);
|
|
385
|
+
};
|
|
386
|
+
});
|
|
387
|
+
</script>
|
|
388
|
+
|
|
389
|
+
<div class={cn("csv-sheet-view", className)} {@attach findShortcut}>
|
|
390
|
+
{#if parsed.errors.length > 0}
|
|
391
|
+
<div class="csv-table-view__errors" role="status">
|
|
392
|
+
{#each parsed.errors as error (error)}
|
|
393
|
+
<p>{error}</p>
|
|
394
|
+
{/each}
|
|
395
|
+
</div>
|
|
396
|
+
{/if}
|
|
397
|
+
<CsvFind
|
|
398
|
+
bind:open={searchOpen}
|
|
399
|
+
bind:searchValue
|
|
400
|
+
bind:replaceValue
|
|
401
|
+
bind:caseSensitive
|
|
402
|
+
bind:wholeWord
|
|
403
|
+
bind:regexp
|
|
404
|
+
bind:active
|
|
405
|
+
{searchRequest}
|
|
406
|
+
{rows}
|
|
407
|
+
onReplaceCells={replaceCells}
|
|
408
|
+
/>
|
|
409
|
+
<CsvSheet
|
|
410
|
+
grid={parsed.grid}
|
|
411
|
+
headerRow={settings.headerRow}
|
|
412
|
+
{bodyRows}
|
|
413
|
+
{searchCell}
|
|
414
|
+
sort={columnSort}
|
|
415
|
+
{widths}
|
|
416
|
+
onWidths={rememberWidths}
|
|
417
|
+
onCellChange={changeCell}
|
|
418
|
+
onSort={sortColumn}
|
|
419
|
+
onDeleteRow={deleteRow}
|
|
420
|
+
onDeleteColumn={deleteColumn}
|
|
421
|
+
onMoveColumn={moveColumn}
|
|
422
|
+
onMoveRow={moveRow}
|
|
423
|
+
onClearColumn={clearColumn}
|
|
424
|
+
onClearRow={clearRow}
|
|
425
|
+
onClearCell={clearCell}
|
|
426
|
+
onClearSheet={clearSheet}
|
|
427
|
+
onDeleteSheet={deleteSheet}
|
|
428
|
+
canUndo={history.past.length > 0}
|
|
429
|
+
canRedo={history.future.length > 0}
|
|
430
|
+
onUndo={undoSheet}
|
|
431
|
+
onRedo={redoSheet}
|
|
432
|
+
onHeaderRow={(headerRow) => onSettingsChange?.({ headerRow })}
|
|
433
|
+
/>
|
|
434
|
+
<CsvStatusBar
|
|
435
|
+
columns={counts.columns}
|
|
436
|
+
rows={counts.rows}
|
|
437
|
+
{shownRows}
|
|
438
|
+
{searchOpen}
|
|
439
|
+
mode="canvas"
|
|
440
|
+
onToggleSearch={toggleSearch}
|
|
441
|
+
onShowTable={onShowTable}
|
|
442
|
+
onToggleMode={onToggleSource}
|
|
443
|
+
/>
|
|
444
|
+
</div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { App, TFile } from "@lapis-notes/api";
|
|
2
|
+
import { type CsvPluginSettings } from "../../csv-settings";
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
app: App;
|
|
5
|
+
file: TFile;
|
|
6
|
+
content: string;
|
|
7
|
+
settings: CsvPluginSettings;
|
|
8
|
+
class?: string;
|
|
9
|
+
onContentChange?: (text: string) => void;
|
|
10
|
+
onShowTable?: () => void;
|
|
11
|
+
onToggleSource?: () => void;
|
|
12
|
+
onSettingsChange?: (patch: {
|
|
13
|
+
headerRow?: boolean;
|
|
14
|
+
}) => void;
|
|
15
|
+
};
|
|
16
|
+
declare const CsvSheetView: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
17
|
+
type CsvSheetView = ReturnType<typeof CsvSheetView>;
|
|
18
|
+
export default CsvSheetView;
|