@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.
- package/CHANGELOG.md +22 -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,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,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;
|