@pixerate/editor-svelte 0.24.0 → 0.25.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 -1
- package/dist/ExportDocxButton.svelte +48 -0
- package/dist/ExportDocxButton.svelte.d.ts +13 -0
- package/dist/ExportDocxButton.svelte.d.ts.map +1 -0
- package/dist/canvas/AnimationTimeline.svelte +217 -0
- package/dist/canvas/AnimationTimeline.svelte.d.ts +20 -0
- package/dist/canvas/AnimationTimeline.svelte.d.ts.map +1 -0
- package/dist/canvas/CanvasComponentsPanel.svelte +73 -0
- package/dist/canvas/CanvasComponentsPanel.svelte.d.ts +13 -0
- package/dist/canvas/CanvasComponentsPanel.svelte.d.ts.map +1 -0
- package/dist/canvas/CanvasInstanceInspector.svelte +136 -0
- package/dist/canvas/CanvasInstanceInspector.svelte.d.ts +16 -0
- package/dist/canvas/CanvasInstanceInspector.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasAnimation.svelte.d.ts +98 -0
- package/dist/canvas/createCanvasAnimation.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasAnimation.svelte.js +79 -0
- package/dist/canvas/createCanvasArrange.svelte.d.ts.map +1 -1
- package/dist/canvas/createCanvasAutoLayout.svelte.d.ts.map +1 -1
- package/dist/canvas/createCanvasComponents.svelte.d.ts +68 -0
- package/dist/canvas/createCanvasComponents.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasComponents.svelte.js +31 -0
- package/dist/canvas/index.d.ts +7 -0
- package/dist/canvas/index.d.ts.map +1 -1
- package/dist/canvas/index.js +9 -0
- package/dist/docxExport.svelte.d.ts +26 -0
- package/dist/docxExport.svelte.d.ts.map +1 -0
- package/dist/docxExport.svelte.js +36 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/spreadsheet/SpreadsheetEditor.svelte +77 -7
- package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts +6 -0
- package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/SpreadsheetGroupRow.svelte +31 -3
- package/dist/spreadsheet/SpreadsheetGroupRow.svelte.d.ts +6 -0
- package/dist/spreadsheet/SpreadsheetGroupRow.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/index.d.ts +1 -0
- package/dist/spreadsheet/index.d.ts.map +1 -1
- package/dist/spreadsheet/index.js +1 -0
- package/dist/spreadsheet/spreadsheet.svelte.d.ts +1 -1
- package/dist/spreadsheet/spreadsheet.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/viewport.svelte.d.ts +26 -0
- package/dist/spreadsheet/viewport.svelte.d.ts.map +1 -0
- package/dist/spreadsheet/viewport.svelte.js +93 -0
- package/dist/tables/InsertTableGrid.svelte +85 -0
- package/dist/tables/InsertTableGrid.svelte.d.ts +21 -0
- package/dist/tables/InsertTableGrid.svelte.d.ts.map +1 -0
- package/dist/tables/TableBubbleMenu.svelte +43 -0
- package/dist/tables/TableBubbleMenu.svelte.d.ts +18 -0
- package/dist/tables/TableBubbleMenu.svelte.d.ts.map +1 -0
- package/dist/tables/TableToolbar.svelte +81 -0
- package/dist/tables/TableToolbar.svelte.d.ts +19 -0
- package/dist/tables/TableToolbar.svelte.d.ts.map +1 -0
- package/dist/tables/index.d.ts +12 -0
- package/dist/tables/index.d.ts.map +1 -0
- package/dist/tables/index.js +4 -0
- package/dist/tables/tableMenu.svelte.d.ts +21 -0
- package/dist/tables/tableMenu.svelte.d.ts.map +1 -0
- package/dist/tables/tableMenu.svelte.js +27 -0
- package/package.json +2 -2
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
import SheetTabs from './SheetTabs.svelte';
|
|
33
33
|
import { createReactiveSpreadsheet } from './spreadsheet.svelte.js';
|
|
34
34
|
import { attachSpreadsheetClipboard } from './tableInteractions.js';
|
|
35
|
+
import { createSpreadsheetViewport } from './viewport.svelte.js';
|
|
35
36
|
|
|
36
37
|
interface Props {
|
|
37
38
|
sheetState?: ReturnType<typeof createReactiveSpreadsheet>;
|
|
@@ -47,6 +48,12 @@
|
|
|
47
48
|
onColumnResize?: (colId: string, width: number) => void;
|
|
48
49
|
/** Show the sheet tabs bar under the grid (add, switch, rename, reorder, delete sheets). */
|
|
49
50
|
showSheetTabs?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Render only the rows and columns in (or near) view. `'auto'` (default)
|
|
53
|
+
* virtualises sheets with more than 200 displayed rows or 60 columns;
|
|
54
|
+
* `true` / `false` force it.
|
|
55
|
+
*/
|
|
56
|
+
virtualize?: boolean | 'auto';
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
let {
|
|
@@ -59,9 +66,51 @@
|
|
|
59
66
|
onAddColumnClick,
|
|
60
67
|
onColumnHeaderClick,
|
|
61
68
|
onColumnResize,
|
|
62
|
-
showSheetTabs = false
|
|
69
|
+
showSheetTabs = false,
|
|
70
|
+
virtualize = 'auto'
|
|
63
71
|
}: Props = $props();
|
|
64
72
|
|
|
73
|
+
// Virtualised rendering: frozen rows/columns, a spacer, the rows and
|
|
74
|
+
// columns in view, another spacer (everything for small sheets).
|
|
75
|
+
type ColumnSlot = { kind: 'col'; key: string; viewCol: SpreadsheetViewColumn } | { kind: 'space'; key: string; width: number };
|
|
76
|
+
type RowSlot = { kind: 'row'; key: string; viewRow: SpreadsheetViewRow } | { kind: 'space'; key: string; height: number };
|
|
77
|
+
let scrollContainer = $state<HTMLDivElement | null>(null);
|
|
78
|
+
const viewportState = createSpreadsheetViewport({
|
|
79
|
+
view: () => sheetState.viewModel,
|
|
80
|
+
virtualize: () => virtualize,
|
|
81
|
+
merges: () => sheetState.document.table?.merges,
|
|
82
|
+
activeCell: () => sheetState.activeCell
|
|
83
|
+
});
|
|
84
|
+
$effect(() => viewportState.attach(scrollContainer));
|
|
85
|
+
let viewWindow = $derived(viewportState.window);
|
|
86
|
+
let columnSlots = $derived.by<ColumnSlot[]>(() => {
|
|
87
|
+
const view = sheetState.viewModel;
|
|
88
|
+
const win = viewWindow;
|
|
89
|
+
const col = (viewCol: SpreadsheetViewColumn): ColumnSlot => ({ kind: 'col', key: viewCol.column.id, viewCol });
|
|
90
|
+
if (!win.virtual) return view.columns.map(col);
|
|
91
|
+
const slots = view.columns.slice(0, win.frozenColumns).map(col);
|
|
92
|
+
if (win.leftSpace > 0) slots.push({ kind: 'space', key: 'space:left', width: win.leftSpace });
|
|
93
|
+
for (let i = win.colStart; i < win.colEnd; i++) slots.push(col(view.columns[i]));
|
|
94
|
+
if (win.rightSpace > 0) slots.push({ kind: 'space', key: 'space:right', width: win.rightSpace });
|
|
95
|
+
return slots;
|
|
96
|
+
});
|
|
97
|
+
let renderedColumns = $derived(columnSlots.flatMap((slot) => (slot.kind === 'col' ? [slot.viewCol] : [])));
|
|
98
|
+
let rowSlots = $derived.by<RowSlot[]>(() => {
|
|
99
|
+
const view = sheetState.viewModel;
|
|
100
|
+
const win = viewWindow;
|
|
101
|
+
const row = (viewRow: SpreadsheetViewRow): RowSlot => ({
|
|
102
|
+
kind: 'row',
|
|
103
|
+
key: viewRow.kind === 'group' ? `group:${viewRow.group.key}` : viewRow.row.id,
|
|
104
|
+
viewRow
|
|
105
|
+
});
|
|
106
|
+
if (!win.virtual) return view.rows.map(row);
|
|
107
|
+
const slots = view.rows.slice(0, win.frozenRows).map(row);
|
|
108
|
+
if (win.topSpace > 0) slots.push({ kind: 'space', key: 'space:top', height: win.topSpace });
|
|
109
|
+
for (let i = win.rowStart; i < win.rowEnd; i++) slots.push(row(view.rows[i]));
|
|
110
|
+
if (win.bottomSpace > 0) slots.push({ kind: 'space', key: 'space:bottom', height: win.bottomSpace });
|
|
111
|
+
return slots;
|
|
112
|
+
});
|
|
113
|
+
|
|
65
114
|
// Defined names for formula autocomplete in the cell editor.
|
|
66
115
|
let nameSuggestions = $derived.by(() => {
|
|
67
116
|
void sheetState.document;
|
|
@@ -554,8 +603,8 @@
|
|
|
554
603
|
{/if}
|
|
555
604
|
|
|
556
605
|
<!-- Main Scrollable Grid -->
|
|
557
|
-
<div class="relative flex-1 overflow-auto">
|
|
558
|
-
<table class="border-
|
|
606
|
+
<div bind:this={scrollContainer} class="relative flex-1 overflow-auto" onscroll={viewportState.onScroll}>
|
|
607
|
+
<table class="border-separate border-spacing-0 table-fixed w-max min-w-full [&>*>tr:not([data-spacer])>*]:border-b [&>*>tr>*]:border-border">
|
|
559
608
|
<!-- Table Header Columns -->
|
|
560
609
|
<thead>
|
|
561
610
|
<tr class="h-7 bg-muted sticky top-0 z-20 border-b border-border shadow-xs">
|
|
@@ -563,7 +612,11 @@
|
|
|
563
612
|
<th class="w-12 min-w-[3rem] sticky left-0 z-30 bg-muted border-r border-border text-center text-[10px] text-muted-foreground font-medium">
|
|
564
613
|
#
|
|
565
614
|
</th>
|
|
566
|
-
{#each
|
|
615
|
+
{#each columnSlots as slot (slot.key)}
|
|
616
|
+
{#if slot.kind === 'space'}
|
|
617
|
+
<th aria-hidden="true" data-spacer="" class="p-0" style="width: {slot.width}px; min-width: {slot.width}px; max-width: {slot.width}px; padding: 0;"></th>
|
|
618
|
+
{:else}
|
|
619
|
+
{@const viewCol = slot.viewCol}
|
|
567
620
|
{@const col = viewCol.column}
|
|
568
621
|
{@const cIdx = viewCol.index}
|
|
569
622
|
<th
|
|
@@ -599,6 +652,7 @@
|
|
|
599
652
|
></div>
|
|
600
653
|
</div>
|
|
601
654
|
</th>
|
|
655
|
+
{/if}
|
|
602
656
|
{/each}
|
|
603
657
|
{#if onAddColumnClick}
|
|
604
658
|
<th class="w-10 min-w-[2.5rem] px-1 text-center bg-muted/40 hover:bg-muted cursor-pointer transition-colors" onclick={onAddColumnClick} title="Add Column">
|
|
@@ -612,11 +666,21 @@
|
|
|
612
666
|
|
|
613
667
|
<!-- Table Body Rows -->
|
|
614
668
|
<tbody>
|
|
615
|
-
{#each
|
|
669
|
+
{#each rowSlots as rowSlot (rowSlot.key)}
|
|
670
|
+
{#if rowSlot.kind === 'space'}
|
|
671
|
+
<tr aria-hidden="true" data-spacer="" style="height: {rowSlot.height}px;">
|
|
672
|
+
<td colspan={columnSlots.length + 3} style="padding: 0; border: 0;"></td>
|
|
673
|
+
</tr>
|
|
674
|
+
{:else}
|
|
675
|
+
{@const viewRow = rowSlot.viewRow}
|
|
616
676
|
{#if viewRow.kind === 'group'}
|
|
617
677
|
<SpreadsheetGroupRow
|
|
618
678
|
group={viewRow.group}
|
|
619
|
-
columns={
|
|
679
|
+
columns={renderedColumns}
|
|
680
|
+
labelColumns={sheetState.viewModel.columns}
|
|
681
|
+
leadingColumns={viewWindow.virtual ? viewWindow.frozenColumns : undefined}
|
|
682
|
+
leftSpace={viewWindow.leftSpace}
|
|
683
|
+
rightSpace={viewWindow.rightSpace}
|
|
620
684
|
groupColId={sheetState.document.table?.grouping?.colId ?? ''}
|
|
621
685
|
onToggle={sheetState.toggleGroupCollapsed}
|
|
622
686
|
trailingCell={!!onAddColumnClick}
|
|
@@ -637,7 +701,11 @@
|
|
|
637
701
|
</td>
|
|
638
702
|
|
|
639
703
|
<!-- Cells (a merged cell renders its top-left cell, spanning the merge) -->
|
|
640
|
-
{#each
|
|
704
|
+
{#each columnSlots as slot (slot.key)}
|
|
705
|
+
{#if slot.kind === 'space'}
|
|
706
|
+
<td aria-hidden="true" data-spacer="" style="padding: 0;"></td>
|
|
707
|
+
{:else}
|
|
708
|
+
{@const viewCol = slot.viewCol}
|
|
641
709
|
{@const span = sheetState.viewModel.getCellSpan(displayRowIndex, viewCol.index)}
|
|
642
710
|
{#if span}
|
|
643
711
|
{@const rIdx = span.source.row}
|
|
@@ -752,6 +820,7 @@
|
|
|
752
820
|
{/if}
|
|
753
821
|
</td>
|
|
754
822
|
{/if}
|
|
823
|
+
{/if}
|
|
755
824
|
{/each}
|
|
756
825
|
{#if onAddColumnClick}
|
|
757
826
|
<td class="w-10 min-w-[2.5rem] bg-muted/10 border-r border-border"></td>
|
|
@@ -760,6 +829,7 @@
|
|
|
760
829
|
<td class="border-b border-border bg-transparent p-0"></td>
|
|
761
830
|
</tr>
|
|
762
831
|
{/if}
|
|
832
|
+
{/if}
|
|
763
833
|
{/each}
|
|
764
834
|
</tbody>
|
|
765
835
|
</table>
|
|
@@ -17,6 +17,12 @@ interface Props {
|
|
|
17
17
|
onColumnResize?: (colId: string, width: number) => void;
|
|
18
18
|
/** Show the sheet tabs bar under the grid (add, switch, rename, reorder, delete sheets). */
|
|
19
19
|
showSheetTabs?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Render only the rows and columns in (or near) view. `'auto'` (default)
|
|
22
|
+
* virtualises sheets with more than 200 displayed rows or 60 columns;
|
|
23
|
+
* `true` / `false` force it.
|
|
24
|
+
*/
|
|
25
|
+
virtualize?: boolean | 'auto';
|
|
20
26
|
}
|
|
21
27
|
declare const SpreadsheetEditor: import("svelte").Component<Props, {}, "">;
|
|
22
28
|
type SpreadsheetEditor = ReturnType<typeof SpreadsheetEditor>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpreadsheetEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/spreadsheet/SpreadsheetEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAMH,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,QAAQ,EAad,MAAM,8BAA8B,CAAC;AASxC,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"SpreadsheetEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/spreadsheet/SpreadsheetEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAMH,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,QAAQ,EAad,MAAM,8BAA8B,CAAC;AASxC,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAKlE,UAAU,KAAK;IACb,UAAU,CAAC,EAAE,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC;IAC1D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EACf,OAAO,CAAC,CAAC,QAAQ,EAAE,iBAAiB,EAAE,cAAc,CAAC,CAAC,GACtD,OAAO,CAAC,CAAC;QAAE,GAAG,EAAE,cAAc,CAAC;QAAC,GAAG,EAAE,iBAAiB,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,CAAC,CAAC,CAAC;IAC/E,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACvD,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,4FAA4F;IAC5F,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAC/B;AAsvBH,QAAA,MAAM,iBAAiB,2CAAwC,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
|
|
@@ -9,12 +9,31 @@
|
|
|
9
9
|
onToggle: (key: string) => void;
|
|
10
10
|
/** Render a trailing cell for the "add column" column. */
|
|
11
11
|
trailingCell?: boolean;
|
|
12
|
+
/** Every displayed column, when `columns` is a virtualised window of them (picks the label column). */
|
|
13
|
+
labelColumns?: SpreadsheetViewColumn[];
|
|
14
|
+
/** Virtualised: columns before the left spacer (the frozen ones), and the spacers' widths. */
|
|
15
|
+
leadingColumns?: number;
|
|
16
|
+
leftSpace?: number;
|
|
17
|
+
rightSpace?: number;
|
|
12
18
|
}
|
|
13
19
|
|
|
14
|
-
let {
|
|
20
|
+
let {
|
|
21
|
+
group,
|
|
22
|
+
columns,
|
|
23
|
+
groupColId,
|
|
24
|
+
onToggle,
|
|
25
|
+
trailingCell = false,
|
|
26
|
+
labelColumns,
|
|
27
|
+
leadingColumns,
|
|
28
|
+
leftSpace = 0,
|
|
29
|
+
rightSpace = 0
|
|
30
|
+
}: Props = $props();
|
|
15
31
|
|
|
16
32
|
// The label goes in the grouping column, or the first column when that one is hidden.
|
|
17
|
-
let labelColId = $derived
|
|
33
|
+
let labelColId = $derived.by(() => {
|
|
34
|
+
const candidates = labelColumns ?? columns;
|
|
35
|
+
return candidates.some((c) => c.column.id === groupColId) ? groupColId : candidates[0]?.column.id;
|
|
36
|
+
});
|
|
18
37
|
|
|
19
38
|
const formatSummary = (value: number | null) => (value === null ? '–' : String(value));
|
|
20
39
|
</script>
|
|
@@ -35,8 +54,11 @@
|
|
|
35
54
|
{group.collapsed ? '▸' : '▾'}
|
|
36
55
|
</button>
|
|
37
56
|
</td>
|
|
38
|
-
{#each columns as { column } (column.id)}
|
|
57
|
+
{#each columns as { column }, i (column.id)}
|
|
39
58
|
{@const summary = group.summaries[column.id]}
|
|
59
|
+
{#if leadingColumns !== undefined && i === leadingColumns && leftSpace > 0}
|
|
60
|
+
<td aria-hidden="true" data-spacer="" style="padding: 0;"></td>
|
|
61
|
+
{/if}
|
|
40
62
|
<td class="border-r border-border px-2 py-1 truncate max-w-0 text-foreground" style="max-width: 0; overflow: hidden;">
|
|
41
63
|
{#if column.id === labelColId}
|
|
42
64
|
<span class="truncate">
|
|
@@ -47,6 +69,12 @@
|
|
|
47
69
|
{/if}
|
|
48
70
|
</td>
|
|
49
71
|
{/each}
|
|
72
|
+
{#if leadingColumns !== undefined && leadingColumns >= columns.length && leftSpace > 0}
|
|
73
|
+
<td aria-hidden="true" data-spacer="" style="padding: 0;"></td>
|
|
74
|
+
{/if}
|
|
75
|
+
{#if rightSpace > 0}
|
|
76
|
+
<td aria-hidden="true" data-spacer="" style="padding: 0;"></td>
|
|
77
|
+
{/if}
|
|
50
78
|
{#if trailingCell}
|
|
51
79
|
<td class="w-10 min-w-[2.5rem] bg-muted/10 border-r border-border"></td>
|
|
52
80
|
{/if}
|
|
@@ -7,6 +7,12 @@ interface Props {
|
|
|
7
7
|
onToggle: (key: string) => void;
|
|
8
8
|
/** Render a trailing cell for the "add column" column. */
|
|
9
9
|
trailingCell?: boolean;
|
|
10
|
+
/** Every displayed column, when `columns` is a virtualised window of them (picks the label column). */
|
|
11
|
+
labelColumns?: SpreadsheetViewColumn[];
|
|
12
|
+
/** Virtualised: columns before the left spacer (the frozen ones), and the spacers' widths. */
|
|
13
|
+
leadingColumns?: number;
|
|
14
|
+
leftSpace?: number;
|
|
15
|
+
rightSpace?: number;
|
|
10
16
|
}
|
|
11
17
|
declare const SpreadsheetGroupRow: import("svelte").Component<Props, {}, "">;
|
|
12
18
|
type SpreadsheetGroupRow = ReturnType<typeof SpreadsheetGroupRow>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpreadsheetGroupRow.svelte.d.ts","sourceRoot":"","sources":["../../src/spreadsheet/SpreadsheetGroupRow.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAG7F,UAAU,KAAK;IACb,KAAK,EAAE,mBAAmB,CAAC;IAC3B,OAAO,EAAE,qBAAqB,EAAE,CAAC;IACjC,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,0DAA0D;IAC1D,YAAY,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SpreadsheetGroupRow.svelte.d.ts","sourceRoot":"","sources":["../../src/spreadsheet/SpreadsheetGroupRow.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAG7F,UAAU,KAAK;IACb,KAAK,EAAE,mBAAmB,CAAC;IAC3B,OAAO,EAAE,qBAAqB,EAAE,CAAC;IACjC,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,0DAA0D;IAC1D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uGAAuG;IACvG,YAAY,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACvC,8FAA8F;IAC9F,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAkEH,QAAA,MAAM,mBAAmB,2CAAwC,CAAC;AAClE,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAClE,eAAe,mBAAmB,CAAC"}
|
|
@@ -21,4 +21,5 @@ export type FormulaBarProps = ComponentProps<typeof FormulaBarComponent>;
|
|
|
21
21
|
export type FormulaHintsProps = ComponentProps<typeof FormulaHintsComponent>;
|
|
22
22
|
export type SheetTabsProps = ComponentProps<typeof SheetTabsComponent>;
|
|
23
23
|
export type NameManagerProps = ComponentProps<typeof NameManagerComponent>;
|
|
24
|
+
export * from './viewport.svelte.js';
|
|
24
25
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/spreadsheet/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,0BAA0B,MAAM,4BAA4B,CAAC;AACzE,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,kBAAkB,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAE7D,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,cAAc,wBAAwB,CAAC;AACvC,OAAO,EAAE,OAAO,IAAI,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AAC9F,OAAO,EAAE,OAAO,IAAI,iCAAiC,EAAE,MAAM,4CAA4C,CAAC;AAC1G,OAAO,EAAE,OAAO,IAAI,8BAA8B,EAAE,MAAM,yCAAyC,CAAC;AAEpG,MAAM,MAAM,sBAAsB,GAAG,cAAc,CAAC,OAAO,0BAA0B,CAAC,CAAC;AACvF,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC7E,MAAM,MAAM,cAAc,GAAG,cAAc,CAAC,OAAO,kBAAkB,CAAC,CAAC;AACvE,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/spreadsheet/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,0BAA0B,MAAM,4BAA4B,CAAC;AACzE,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,kBAAkB,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAE7D,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,cAAc,wBAAwB,CAAC;AACvC,OAAO,EAAE,OAAO,IAAI,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AAC9F,OAAO,EAAE,OAAO,IAAI,iCAAiC,EAAE,MAAM,4CAA4C,CAAC;AAC1G,OAAO,EAAE,OAAO,IAAI,8BAA8B,EAAE,MAAM,yCAAyC,CAAC;AAEpG,MAAM,MAAM,sBAAsB,GAAG,cAAc,CAAC,OAAO,0BAA0B,CAAC,CAAC;AACvF,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC7E,MAAM,MAAM,cAAc,GAAG,cAAc,CAAC,OAAO,kBAAkB,CAAC,CAAC;AACvE,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,cAAc,sBAAsB,CAAC"}
|
|
@@ -10,3 +10,4 @@ export * from './tableInteractions.js';
|
|
|
10
10
|
export { default as SpreadsheetValidationDialog } from './SpreadsheetValidationDialog.svelte';
|
|
11
11
|
export { default as SpreadsheetConditionalFormatPanel } from './SpreadsheetConditionalFormatPanel.svelte';
|
|
12
12
|
export { default as SpreadsheetDataValidationPanel } from './SpreadsheetDataValidationPanel.svelte';
|
|
13
|
+
export * from './viewport.svelte.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SpreadsheetController, type SpreadsheetControllerOptions, type SpreadsheetDocument, type CellCoordinate, type CellRange, type CellData, type SpreadsheetColumn, type SpreadsheetRow, type SpreadsheetDataSource, type SpreadsheetNameScope, type SpreadsheetCommitResult, type SpreadsheetValidationAction, type SpreadsheetValidationPrompt } from '@pixerate/editor/spreadsheet';
|
|
2
2
|
export declare function createReactiveSpreadsheet(options?: SpreadsheetControllerOptions): {
|
|
3
|
+
mergeCells: (range?: CellRange | null) => boolean;
|
|
3
4
|
sortRows: (keys: import("@pixerate/editor").SortKey[], options?: {
|
|
4
5
|
range?: CellRange | null;
|
|
5
6
|
}) => boolean;
|
|
@@ -23,7 +24,6 @@ export declare function createReactiveSpreadsheet(options?: SpreadsheetControlle
|
|
|
23
24
|
unhideAll: () => void;
|
|
24
25
|
getMerges: () => CellRange[];
|
|
25
26
|
getMergeAt: (row: number, col: number) => CellRange | null;
|
|
26
|
-
mergeCells: (range?: CellRange | null) => boolean;
|
|
27
27
|
unmergeCells: (range?: CellRange | null) => boolean;
|
|
28
28
|
autofill: (source: CellRange, target: CellRange) => boolean;
|
|
29
29
|
groupRowsBy: (colId: string, summaries?: import("@pixerate/editor").GroupSummary[]) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spreadsheet.svelte.d.ts","sourceRoot":"","sources":["../../src/spreadsheet/spreadsheet.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EAErB,KAAK,4BAA4B,EACjC,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EACjC,MAAM,8BAA8B,CAAC;AAEtC,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,4BAAiC
|
|
1
|
+
{"version":3,"file":"spreadsheet.svelte.d.ts","sourceRoot":"","sources":["../../src/spreadsheet/spreadsheet.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EAErB,KAAK,4BAA4B,EACjC,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EACjC,MAAM,8BAA8B,CAAC;AAEtC,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,4BAAiC;;;aAyRmx0D,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBAA06W,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;gBAnK3vrE,MAAM;;;;;mBAMX,MAAM,SAAS,MAAM,GAAG,QAAQ;wBAG3B,MAAM,SAAS,MAAM,OAAO,MAAM;oBAItC,MAAM,OAAO,MAAM;uBAKhB,SAAS;uBAIT,MAAM,QAAQ,MAAM,eAAe,MAAM;;;wBAYxC,MAAM,GAAG,uBAAuB;IAKpD,+FAA+F;2BACxE,MAAM,SAAS,MAAM,OAAO,MAAM,GAAG,uBAAuB;IAKnF,qFAAqF;oCACrD,2BAA2B;;oBAS3C,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO;wBAK5B,MAAM,WAAW,OAAO,CAAC,iBAAiB,CAAC;wBAI3C,MAAM;qBAIT,MAAM,WAAW,OAAO,CAAC,cAAc,CAAC;qBAIxC,MAAM;0BAID,MAAM,SAAS,MAAM;8BAIjB,MAAM,gBAAgB,MAAM;2BAI/B,mBAAmB;;2BAanB,qBAAqB;6BAInB,MAAM,GAAG,SAAS;;wBAQvB,SAAS,GAAG,IAAI;wBAGhB,MAAM;;;6BAaD,MAAM;uBAKZ,UAAU;YAiCqxgE,CAAC;aAAuB,CAAC;gBAA0B,CAAC;gBAAgD,CAAC;iBAjC91gE,CAAC,CAAC,CAAC;0BAKtC,MAAM,WAAW,MAAM;wBAGzB,MAAM,WAAW,MAAM;0BAGrB,MAAM;6BAKH,MAAM,YAAY,UAAU;YAiBk4iE,CAAC;aAAuB,CAAC;gBAA0B,CAAC;wBAjBp5iE,CAAC,CAAC,CAAC;qBAKzE,MAAM,YAAY,MAAM,YAAY,oBAAoB,GAAG;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;wBAG5E,MAAM,WAAW,MAAM,YAAY,oBAAoB;qBAG1D,MAAM,YAAY,oBAAoB;EAK1D"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type CellCoordinate, type CellRange, type SpreadsheetViewModel } from '@pixerate/editor/spreadsheet';
|
|
2
|
+
export interface SpreadsheetViewportSource {
|
|
3
|
+
view: () => SpreadsheetViewModel;
|
|
4
|
+
/** `'auto'` (default): virtualise large views only; `true` / `false` force it. */
|
|
5
|
+
virtualize?: () => boolean | 'auto' | undefined;
|
|
6
|
+
/** Merged ranges, rendered whole when they cross the window's edge. */
|
|
7
|
+
merges?: () => readonly CellRange[] | undefined;
|
|
8
|
+
/** Scrolled into view when it changes (virtualised views only). */
|
|
9
|
+
activeCell?: () => CellCoordinate | null | undefined;
|
|
10
|
+
overscanRows?: number;
|
|
11
|
+
overscanColumns?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Virtualised rendering for `SpreadsheetEditor` (the Svelte counterpart of
|
|
15
|
+
* React's `useSpreadsheetViewport`): tracks the scroll container passed to
|
|
16
|
+
* `attach`, works out the window of rows and columns to render, and scrolls
|
|
17
|
+
* the active cell into view. Call it while a component initialises.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createSpreadsheetViewport(source: SpreadsheetViewportSource): {
|
|
20
|
+
readonly metrics: import("@pixerate/editor").SpreadsheetViewMetrics;
|
|
21
|
+
/** What to render; `virtual: false` renders every row and column. */
|
|
22
|
+
readonly window: import("@pixerate/editor").SpreadsheetViewWindow;
|
|
23
|
+
onScroll: () => void;
|
|
24
|
+
attach: (el: HTMLElement | null) => () => void;
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=viewport.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewport.svelte.d.ts","sourceRoot":"","sources":["../../src/spreadsheet/viewport.svelte.ts"],"names":[],"mappings":"AACA,OAAO,EAOL,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,oBAAoB,EAG1B,MAAM,8BAA8B,CAAC;AAEtC,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,oBAAoB,CAAC;IACjC,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IAChD,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,SAAS,SAAS,EAAE,GAAG,SAAS,CAAC;IAChD,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC;IACrD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,yBAAyB;;IA4EvE,qEAAqE;;;iBAxCnD,WAAW,GAAG,IAAI,KAAG,MAAM,IAAI;EA+CpD"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { untrack } from 'svelte';
|
|
2
|
+
import { fullSpreadsheetViewWindow, getSpreadsheetScrollToCell, getSpreadsheetViewWindow, measureSpreadsheetView, sameSpreadsheetViewWindow, shouldVirtualizeSpreadsheet } from '@pixerate/editor/spreadsheet';
|
|
3
|
+
/**
|
|
4
|
+
* Virtualised rendering for `SpreadsheetEditor` (the Svelte counterpart of
|
|
5
|
+
* React's `useSpreadsheetViewport`): tracks the scroll container passed to
|
|
6
|
+
* `attach`, works out the window of rows and columns to render, and scrolls
|
|
7
|
+
* the active cell into view. Call it while a component initialises.
|
|
8
|
+
*/
|
|
9
|
+
export function createSpreadsheetViewport(source) {
|
|
10
|
+
let viewport = $state.raw({ scrollTop: 0, scrollLeft: 0, width: 0, height: 0 });
|
|
11
|
+
let element = null;
|
|
12
|
+
const metrics = $derived(measureSpreadsheetView(source.view()));
|
|
13
|
+
const virtual = $derived(shouldVirtualizeSpreadsheet(source.view(), source.virtualize?.() ?? 'auto'));
|
|
14
|
+
const windowOptions = $derived({
|
|
15
|
+
merges: source.merges?.(),
|
|
16
|
+
overscanRows: source.overscanRows,
|
|
17
|
+
overscanColumns: source.overscanColumns
|
|
18
|
+
});
|
|
19
|
+
const win = $derived(virtual ? getSpreadsheetViewWindow(metrics, viewport, windowOptions) : fullSpreadsheetViewWindow(metrics));
|
|
20
|
+
const read = (el) => ({
|
|
21
|
+
scrollTop: el.scrollTop,
|
|
22
|
+
scrollLeft: el.scrollLeft,
|
|
23
|
+
width: el.clientWidth,
|
|
24
|
+
height: el.clientHeight
|
|
25
|
+
});
|
|
26
|
+
/** Stores a new viewport, re-rendering only when the window it gives changes. */
|
|
27
|
+
function update(next) {
|
|
28
|
+
if (!virtual)
|
|
29
|
+
return;
|
|
30
|
+
const prev = viewport;
|
|
31
|
+
const same = prev.width === next.width &&
|
|
32
|
+
prev.height === next.height &&
|
|
33
|
+
sameSpreadsheetViewWindow(getSpreadsheetViewWindow(metrics, prev, windowOptions), getSpreadsheetViewWindow(metrics, next, windowOptions));
|
|
34
|
+
if (!same)
|
|
35
|
+
viewport = next;
|
|
36
|
+
}
|
|
37
|
+
function onScroll() {
|
|
38
|
+
if (element)
|
|
39
|
+
update(read(element));
|
|
40
|
+
}
|
|
41
|
+
/** Tracks `el` (the scroll container); returns a cleanup function. */
|
|
42
|
+
function attach(el) {
|
|
43
|
+
element = el;
|
|
44
|
+
if (!el)
|
|
45
|
+
return () => { };
|
|
46
|
+
onScroll();
|
|
47
|
+
if (typeof ResizeObserver === 'undefined')
|
|
48
|
+
return () => { };
|
|
49
|
+
const observer = new ResizeObserver(() => onScroll());
|
|
50
|
+
observer.observe(el);
|
|
51
|
+
return () => observer.disconnect();
|
|
52
|
+
}
|
|
53
|
+
// Measure once virtualisation turns on (the element may already be attached).
|
|
54
|
+
$effect(() => {
|
|
55
|
+
if (virtual)
|
|
56
|
+
untrack(onScroll);
|
|
57
|
+
});
|
|
58
|
+
// Keyboard navigation and selection: bring the active cell into view.
|
|
59
|
+
// Only the active cell and the mode re-run it: scrolling away from the
|
|
60
|
+
// active cell (or an edit elsewhere) must not snap back.
|
|
61
|
+
$effect(() => {
|
|
62
|
+
const cell = source.activeCell?.();
|
|
63
|
+
const row = cell?.row;
|
|
64
|
+
const col = cell?.col;
|
|
65
|
+
if (!virtual || row === undefined || col === undefined)
|
|
66
|
+
return;
|
|
67
|
+
untrack(() => {
|
|
68
|
+
const base = element ? read(element) : viewport;
|
|
69
|
+
const target = getSpreadsheetScrollToCell(metrics, base, { row, col });
|
|
70
|
+
if (!target)
|
|
71
|
+
return;
|
|
72
|
+
if (element) {
|
|
73
|
+
if (target.scrollTop !== undefined)
|
|
74
|
+
element.scrollTop = target.scrollTop;
|
|
75
|
+
if (target.scrollLeft !== undefined)
|
|
76
|
+
element.scrollLeft = target.scrollLeft;
|
|
77
|
+
}
|
|
78
|
+
// Some environments (jsdom) never fire the scroll event.
|
|
79
|
+
update({ ...base, ...target });
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
return {
|
|
83
|
+
get metrics() {
|
|
84
|
+
return metrics;
|
|
85
|
+
},
|
|
86
|
+
/** What to render; `virtual: false` renders every row and column. */
|
|
87
|
+
get window() {
|
|
88
|
+
return win;
|
|
89
|
+
},
|
|
90
|
+
onScroll,
|
|
91
|
+
attach
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Editor } from "@tiptap/core";
|
|
3
|
+
import { createTableMenu, type SvelteTableMenu } from "./tableMenu.svelte.js";
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
editor?: Editor | null;
|
|
7
|
+
/** Grid size offered (default 8 × 8). */
|
|
8
|
+
rows?: number;
|
|
9
|
+
cols?: number;
|
|
10
|
+
/** Insert with a header row (default `true`). */
|
|
11
|
+
withHeaderRow?: boolean;
|
|
12
|
+
class?: string;
|
|
13
|
+
cellClass?: string;
|
|
14
|
+
activeCellClass?: string;
|
|
15
|
+
/** Called after a table was inserted. */
|
|
16
|
+
oninsert?: (size: { rows: number; cols: number }) => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
editor = null,
|
|
21
|
+
rows = 8,
|
|
22
|
+
cols = 8,
|
|
23
|
+
withHeaderRow = true,
|
|
24
|
+
class: className = "inline-flex flex-col gap-1 rounded-md border border-border bg-background p-2 text-xs shadow-md",
|
|
25
|
+
cellClass = "h-4 w-4 rounded-sm border border-border bg-background disabled:opacity-40",
|
|
26
|
+
activeCellClass = "border-primary bg-primary/20",
|
|
27
|
+
oninsert,
|
|
28
|
+
}: Props = $props();
|
|
29
|
+
|
|
30
|
+
let table = $state.raw<SvelteTableMenu>(createTableMenu(null));
|
|
31
|
+
$effect(() => {
|
|
32
|
+
const menu = createTableMenu(editor);
|
|
33
|
+
table = menu;
|
|
34
|
+
return () => menu.destroy();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
let hover = $state<{ rows: number; cols: number } | null>(null);
|
|
38
|
+
let status = $derived(table.current.actions.insertTable);
|
|
39
|
+
let disabled = $derived(!editor || !status.enabled);
|
|
40
|
+
let sizes = $derived(
|
|
41
|
+
Array.from({ length: rows * cols }, (_, i) => ({ rows: Math.floor(i / cols) + 1, cols: (i % cols) + 1 })),
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const keepSelection = (event: MouseEvent) => event.preventDefault();
|
|
45
|
+
|
|
46
|
+
function insert(size: { rows: number; cols: number }) {
|
|
47
|
+
if (table.run("insertTable", { ...size, withHeaderRow })) oninsert?.(size);
|
|
48
|
+
hover = null;
|
|
49
|
+
}
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<div
|
|
53
|
+
class={className}
|
|
54
|
+
role="group"
|
|
55
|
+
aria-label="Insert table"
|
|
56
|
+
title={disabled ? status.reason : undefined}
|
|
57
|
+
data-insert-table-grid=""
|
|
58
|
+
onmouseleave={() => (hover = null)}
|
|
59
|
+
>
|
|
60
|
+
<div
|
|
61
|
+
role="grid"
|
|
62
|
+
aria-label="Table size"
|
|
63
|
+
style="display: grid; grid-template-columns: repeat({cols}, max-content); gap: 2px"
|
|
64
|
+
>
|
|
65
|
+
{#each sizes as size, i (i)}
|
|
66
|
+
{@const active = !!hover && size.rows <= hover.rows && size.cols <= hover.cols}
|
|
67
|
+
<button
|
|
68
|
+
type="button"
|
|
69
|
+
data-rows={size.rows}
|
|
70
|
+
data-cols={size.cols}
|
|
71
|
+
data-active={active}
|
|
72
|
+
aria-label="{size.rows} × {size.cols} table"
|
|
73
|
+
{disabled}
|
|
74
|
+
class={active ? `${cellClass} ${activeCellClass}` : cellClass}
|
|
75
|
+
onmousedown={keepSelection}
|
|
76
|
+
onmouseenter={() => (hover = size)}
|
|
77
|
+
onfocus={() => (hover = size)}
|
|
78
|
+
onclick={() => insert(size)}
|
|
79
|
+
></button>
|
|
80
|
+
{/each}
|
|
81
|
+
</div>
|
|
82
|
+
<div aria-live="polite" data-testid="insert-table-size">
|
|
83
|
+
{disabled ? status.reason : hover ? `${hover.rows} × ${hover.cols}` : "Insert table"}
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Editor } from "@tiptap/core";
|
|
2
|
+
interface Props {
|
|
3
|
+
editor?: Editor | null;
|
|
4
|
+
/** Grid size offered (default 8 × 8). */
|
|
5
|
+
rows?: number;
|
|
6
|
+
cols?: number;
|
|
7
|
+
/** Insert with a header row (default `true`). */
|
|
8
|
+
withHeaderRow?: boolean;
|
|
9
|
+
class?: string;
|
|
10
|
+
cellClass?: string;
|
|
11
|
+
activeCellClass?: string;
|
|
12
|
+
/** Called after a table was inserted. */
|
|
13
|
+
oninsert?: (size: {
|
|
14
|
+
rows: number;
|
|
15
|
+
cols: number;
|
|
16
|
+
}) => void;
|
|
17
|
+
}
|
|
18
|
+
declare const InsertTableGrid: import("svelte").Component<Props, {}, "">;
|
|
19
|
+
type InsertTableGrid = ReturnType<typeof InsertTableGrid>;
|
|
20
|
+
export default InsertTableGrid;
|
|
21
|
+
//# sourceMappingURL=InsertTableGrid.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InsertTableGrid.svelte.d.ts","sourceRoot":"","sources":["../../src/tables/InsertTableGrid.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAIzC,UAAU,KAAK;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CAC3D;AAqDH,QAAA,MAAM,eAAe,2CAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import type { Editor } from "@tiptap/core";
|
|
4
|
+
import { shouldShowTableBubbleMenu, type TableToolbarItem } from "@pixerate/editor";
|
|
5
|
+
import BubbleMenu from "../BubbleMenu.svelte";
|
|
6
|
+
import TableToolbar from "./TableToolbar.svelte";
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
editor?: Editor;
|
|
10
|
+
class?: string;
|
|
11
|
+
pluginKey?: any;
|
|
12
|
+
updateDelay?: number;
|
|
13
|
+
tippyOptions?: Record<string, any>;
|
|
14
|
+
/** Buttons of the default toolbar. */
|
|
15
|
+
items?: readonly TableToolbarItem[];
|
|
16
|
+
/** Custom content (default: a `TableToolbar`). */
|
|
17
|
+
children?: Snippet;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let {
|
|
21
|
+
editor,
|
|
22
|
+
class: className = "flex h-fit w-fit items-center gap-1 rounded-md border border-gray-200 bg-white p-1 shadow-md",
|
|
23
|
+
pluginKey = "tableBubbleMenu",
|
|
24
|
+
updateDelay = 250,
|
|
25
|
+
tippyOptions = {},
|
|
26
|
+
items,
|
|
27
|
+
children,
|
|
28
|
+
}: Props = $props();
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<!--
|
|
32
|
+
A bubble menu that follows the selection while it is in a table (even a
|
|
33
|
+
collapsed cursor), with the table toolbar or your own children. It uses its
|
|
34
|
+
own plugin key (`tableBubbleMenu`), so it can be combined with the
|
|
35
|
+
formatting `BubbleMenu`.
|
|
36
|
+
-->
|
|
37
|
+
<BubbleMenu {editor} class={className} {pluginKey} {updateDelay} {tippyOptions} shouldShow={shouldShowTableBubbleMenu}>
|
|
38
|
+
{#if children}
|
|
39
|
+
{@render children()}
|
|
40
|
+
{:else}
|
|
41
|
+
<TableToolbar {editor} {...items ? { items } : {}} />
|
|
42
|
+
{/if}
|
|
43
|
+
</BubbleMenu>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
import type { Editor } from "@tiptap/core";
|
|
3
|
+
import { type TableToolbarItem } from "@pixerate/editor";
|
|
4
|
+
interface Props {
|
|
5
|
+
editor?: Editor;
|
|
6
|
+
class?: string;
|
|
7
|
+
pluginKey?: any;
|
|
8
|
+
updateDelay?: number;
|
|
9
|
+
tippyOptions?: Record<string, any>;
|
|
10
|
+
/** Buttons of the default toolbar. */
|
|
11
|
+
items?: readonly TableToolbarItem[];
|
|
12
|
+
/** Custom content (default: a `TableToolbar`). */
|
|
13
|
+
children?: Snippet;
|
|
14
|
+
}
|
|
15
|
+
declare const TableBubbleMenu: import("svelte").Component<Props, {}, "">;
|
|
16
|
+
type TableBubbleMenu = ReturnType<typeof TableBubbleMenu>;
|
|
17
|
+
export default TableBubbleMenu;
|
|
18
|
+
//# sourceMappingURL=TableBubbleMenu.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TableBubbleMenu.svelte.d.ts","sourceRoot":"","sources":["../../src/tables/TableBubbleMenu.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAA6B,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAKlF,UAAU,KAAK;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,GAAG,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC,sCAAsC;IACtC,KAAK,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACpC,kDAAkD;IAClD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA+BH,QAAA,MAAM,eAAe,2CAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
|