@pixerate/editor-svelte 0.18.0 → 0.19.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 +22 -1
- package/dist/EditableTextNodeEditor.svelte +19 -3
- package/dist/EditableTextNodeEditor.svelte.d.ts +5 -1
- package/dist/EditableTextNodeEditor.svelte.d.ts.map +1 -1
- package/dist/OutlinePanel.svelte +85 -0
- package/dist/OutlinePanel.svelte.d.ts +25 -0
- package/dist/OutlinePanel.svelte.d.ts.map +1 -0
- package/dist/TemplateRenderer.svelte +54 -7
- package/dist/TemplateRenderer.svelte.d.ts +8 -1
- package/dist/TemplateRenderer.svelte.d.ts.map +1 -1
- package/dist/VariableForm.svelte +86 -0
- package/dist/VariableForm.svelte.d.ts +21 -0
- package/dist/VariableForm.svelte.d.ts.map +1 -0
- package/dist/agentTools.svelte.d.ts +12 -0
- package/dist/agentTools.svelte.d.ts.map +1 -0
- package/dist/agentTools.svelte.js +17 -0
- package/dist/canvas/CanvasGuidesLayer.svelte +52 -0
- package/dist/canvas/CanvasGuidesLayer.svelte.d.ts +16 -0
- package/dist/canvas/CanvasGuidesLayer.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasArrange.svelte.d.ts +63 -0
- package/dist/canvas/createCanvasArrange.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasArrange.svelte.js +60 -0
- package/dist/canvas/createCanvasScenes.svelte.d.ts +51 -0
- package/dist/canvas/createCanvasScenes.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasScenes.svelte.js +62 -0
- package/dist/canvas/index.d.ts +4 -0
- package/dist/canvas/index.d.ts.map +1 -1
- package/dist/canvas/index.js +5 -0
- package/dist/fileImport.svelte.d.ts +25 -0
- package/dist/fileImport.svelte.d.ts.map +1 -0
- package/dist/fileImport.svelte.js +40 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/outline.svelte.d.ts +18 -0
- package/dist/outline.svelte.d.ts.map +1 -0
- package/dist/outline.svelte.js +27 -0
- package/dist/review/CommentButton.svelte +32 -0
- package/dist/review/CommentButton.svelte.d.ts +10 -0
- package/dist/review/CommentButton.svelte.d.ts.map +1 -0
- package/dist/review/CommentsPanel.svelte +226 -0
- package/dist/review/CommentsPanel.svelte.d.ts +18 -0
- package/dist/review/CommentsPanel.svelte.d.ts.map +1 -0
- package/dist/review/ReviewToolbar.svelte +86 -0
- package/dist/review/ReviewToolbar.svelte.d.ts +9 -0
- package/dist/review/ReviewToolbar.svelte.d.ts.map +1 -0
- package/dist/review/index.d.ts +12 -0
- package/dist/review/index.d.ts.map +1 -0
- package/dist/review/index.js +4 -0
- package/dist/review/review.svelte.d.ts +40 -0
- package/dist/review/review.svelte.d.ts.map +1 -0
- package/dist/review/review.svelte.js +104 -0
- package/dist/spreadsheet/FormulaBar.svelte +13 -5
- package/dist/spreadsheet/FormulaBar.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/FormulaHints.svelte +149 -0
- package/dist/spreadsheet/FormulaHints.svelte.d.ts +14 -0
- package/dist/spreadsheet/FormulaHints.svelte.d.ts.map +1 -0
- package/dist/spreadsheet/SpreadsheetContextMenu.svelte +60 -0
- package/dist/spreadsheet/SpreadsheetContextMenu.svelte.d.ts +11 -0
- package/dist/spreadsheet/SpreadsheetContextMenu.svelte.d.ts.map +1 -0
- package/dist/spreadsheet/SpreadsheetEditor.svelte +172 -19
- package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/SpreadsheetGroupRow.svelte +55 -0
- package/dist/spreadsheet/SpreadsheetGroupRow.svelte.d.ts +14 -0
- package/dist/spreadsheet/SpreadsheetGroupRow.svelte.d.ts.map +1 -0
- package/dist/spreadsheet/index.d.ts +6 -0
- package/dist/spreadsheet/index.d.ts.map +1 -1
- package/dist/spreadsheet/index.js +4 -0
- package/dist/spreadsheet/spreadsheet.svelte.d.ts +42 -4
- package/dist/spreadsheet/spreadsheet.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/spreadsheet.svelte.js +16 -2
- package/dist/spreadsheet/tableInteractions.d.ts +28 -0
- package/dist/spreadsheet/tableInteractions.d.ts.map +1 -0
- package/dist/spreadsheet/tableInteractions.js +61 -0
- package/package.json +2 -2
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Editor } from "@tiptap/core";
|
|
3
|
+
import {
|
|
4
|
+
formatReviewTime,
|
|
5
|
+
getCommentAuthor,
|
|
6
|
+
type CommentStore,
|
|
7
|
+
type CommentThread,
|
|
8
|
+
type ReviewAuthor,
|
|
9
|
+
} from "@pixerate/editor";
|
|
10
|
+
import { createComments, type SvelteComments } from "./review.svelte.js";
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
editor?: Editor | null;
|
|
14
|
+
/** Defaults to the store of the editor's `Comments` extension. */
|
|
15
|
+
store?: CommentStore;
|
|
16
|
+
/** Author of replies. Defaults to the `Comments` extension's author. */
|
|
17
|
+
author?: ReviewAuthor;
|
|
18
|
+
/** Initially show resolved threads. */
|
|
19
|
+
showResolved?: boolean;
|
|
20
|
+
class?: string;
|
|
21
|
+
formatTime?: (timestamp: number) => string;
|
|
22
|
+
emptyMessage?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let {
|
|
26
|
+
editor = null,
|
|
27
|
+
store: storeProp = undefined,
|
|
28
|
+
author: authorProp = undefined,
|
|
29
|
+
showResolved: showResolvedInitial = false,
|
|
30
|
+
class: className = "flex flex-col gap-2 text-sm text-foreground",
|
|
31
|
+
formatTime = (t: number) => formatReviewTime(t),
|
|
32
|
+
emptyMessage = "No comments yet. Select text and add a comment.",
|
|
33
|
+
}: Props = $props();
|
|
34
|
+
|
|
35
|
+
const buttonClass =
|
|
36
|
+
"rounded px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-50";
|
|
37
|
+
const primaryButtonClass =
|
|
38
|
+
"rounded px-2 py-1 text-xs bg-primary/10 text-primary hover:bg-primary/20 disabled:opacity-50";
|
|
39
|
+
const textareaClass =
|
|
40
|
+
"w-full resize-y rounded-md border border-input bg-background p-2 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-primary";
|
|
41
|
+
|
|
42
|
+
// svelte-ignore state_referenced_locally
|
|
43
|
+
let showResolved = $state(showResolvedInitial);
|
|
44
|
+
let drafts = $state<Record<string, string>>({});
|
|
45
|
+
let comments = $state.raw<SvelteComments>(createComments(null));
|
|
46
|
+
|
|
47
|
+
$effect(() => {
|
|
48
|
+
const c = createComments(storeProp ?? editor);
|
|
49
|
+
comments = c;
|
|
50
|
+
return () => c.destroy();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
let author = $derived(
|
|
54
|
+
authorProp ?? getCommentAuthor(editor) ?? { id: "anonymous", name: "Anonymous" },
|
|
55
|
+
);
|
|
56
|
+
let threads = $derived(comments.threads);
|
|
57
|
+
let visible = $derived(threads.filter((t) => showResolved || !t.resolved));
|
|
58
|
+
let resolvedCount = $derived(threads.filter((t) => t.resolved).length);
|
|
59
|
+
|
|
60
|
+
const live = () => (editor && !editor.isDestroyed ? editor : null);
|
|
61
|
+
|
|
62
|
+
function focus(thread: CommentThread) {
|
|
63
|
+
if (thread.id === comments.activeThreadId) return;
|
|
64
|
+
const e = live();
|
|
65
|
+
if (e && !thread.orphaned) e.commands.focusComment(thread.id);
|
|
66
|
+
else comments.store?.setActiveThread(thread.id);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function remove(thread: CommentThread) {
|
|
70
|
+
const e = live();
|
|
71
|
+
if (e) e.commands.deleteComment(thread.id);
|
|
72
|
+
else comments.store?.deleteThread(thread.id);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function setResolved(thread: CommentThread, resolved: boolean) {
|
|
76
|
+
const e = live();
|
|
77
|
+
if (e) e.commands.resolveComment(thread.id, resolved);
|
|
78
|
+
else comments.store?.resolveThread(thread.id, resolved, author);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function submit(thread: CommentThread) {
|
|
82
|
+
const body = (drafts[thread.id] ?? "").trim();
|
|
83
|
+
const store = comments.store;
|
|
84
|
+
if (!body || !store) return;
|
|
85
|
+
if (thread.body === "") store.editComment(thread.id, body);
|
|
86
|
+
else store.addReply(thread.id, { body, author });
|
|
87
|
+
drafts[thread.id] = "";
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function onCardKeydown(event: KeyboardEvent, thread: CommentThread) {
|
|
91
|
+
if (event.target === event.currentTarget && (event.key === "Enter" || event.key === " ")) {
|
|
92
|
+
event.preventDefault();
|
|
93
|
+
focus(thread);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function onTextareaKeydown(event: KeyboardEvent, thread: CommentThread) {
|
|
98
|
+
if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) {
|
|
99
|
+
event.preventDefault();
|
|
100
|
+
submit(thread);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
</script>
|
|
104
|
+
|
|
105
|
+
<aside class={className} aria-label="Comments">
|
|
106
|
+
<div class="flex items-center justify-between gap-2">
|
|
107
|
+
<span class="text-xs font-medium text-muted-foreground">
|
|
108
|
+
{threads.length - resolvedCount} open{resolvedCount > 0 ? ` · ${resolvedCount} resolved` : ""}
|
|
109
|
+
</span>
|
|
110
|
+
{#if resolvedCount > 0}
|
|
111
|
+
<button
|
|
112
|
+
type="button"
|
|
113
|
+
class={buttonClass}
|
|
114
|
+
aria-pressed={showResolved}
|
|
115
|
+
onclick={() => (showResolved = !showResolved)}
|
|
116
|
+
>
|
|
117
|
+
{showResolved ? "Hide resolved" : "Show resolved"}
|
|
118
|
+
</button>
|
|
119
|
+
{/if}
|
|
120
|
+
</div>
|
|
121
|
+
{#if visible.length === 0}
|
|
122
|
+
<p class="text-xs text-muted-foreground">{emptyMessage}</p>
|
|
123
|
+
{:else}
|
|
124
|
+
<ul class="flex flex-col gap-2" role="list">
|
|
125
|
+
{#each visible as thread (thread.id)}
|
|
126
|
+
{@const active = thread.id === comments.activeThreadId}
|
|
127
|
+
{@const isDraft = thread.body === ""}
|
|
128
|
+
{@const quote = thread.anchor?.quote ?? thread.lastQuote ?? ""}
|
|
129
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex, a11y_no_noninteractive_element_interactions -->
|
|
130
|
+
<li
|
|
131
|
+
class={`flex flex-col gap-2 rounded-md border bg-background p-3 cursor-pointer ${
|
|
132
|
+
active ? "border-primary ring-1 ring-primary" : "border-border"
|
|
133
|
+
} ${thread.resolved ? "opacity-70" : ""}`}
|
|
134
|
+
data-thread-id={thread.id}
|
|
135
|
+
data-active={active || undefined}
|
|
136
|
+
aria-current={active || undefined}
|
|
137
|
+
tabindex="0"
|
|
138
|
+
onclick={() => focus(thread)}
|
|
139
|
+
onkeydown={(e) => onCardKeydown(e, thread)}
|
|
140
|
+
>
|
|
141
|
+
<div class="flex items-baseline justify-between gap-2">
|
|
142
|
+
<span class="font-medium">{thread.author.name}</span>
|
|
143
|
+
<span class="text-xs text-muted-foreground">{formatTime(thread.createdAt)}</span>
|
|
144
|
+
</div>
|
|
145
|
+
{#if quote}
|
|
146
|
+
<blockquote class="border-l-2 border-border pl-2 text-xs text-muted-foreground line-clamp-2">
|
|
147
|
+
{quote}
|
|
148
|
+
</blockquote>
|
|
149
|
+
{/if}
|
|
150
|
+
{#if thread.orphaned}
|
|
151
|
+
<span class="text-xs text-destructive">The commented text was deleted.</span>
|
|
152
|
+
{/if}
|
|
153
|
+
{#if thread.resolved}
|
|
154
|
+
<span class="text-xs text-muted-foreground">Resolved</span>
|
|
155
|
+
{/if}
|
|
156
|
+
{#if !isDraft}
|
|
157
|
+
<p class="whitespace-pre-wrap break-words">{thread.body}</p>
|
|
158
|
+
{/if}
|
|
159
|
+
{#if thread.replies.length > 0}
|
|
160
|
+
<ul class="flex flex-col gap-2 border-l border-border pl-3" role="list">
|
|
161
|
+
{#each thread.replies as reply (reply.id)}
|
|
162
|
+
<li class="flex flex-col gap-0.5" data-reply-id={reply.id}>
|
|
163
|
+
<span class="text-xs">
|
|
164
|
+
<span class="font-medium">{reply.author.name}</span>
|
|
165
|
+
<span class="text-muted-foreground">{formatTime(reply.createdAt)}</span>
|
|
166
|
+
</span>
|
|
167
|
+
<p class="whitespace-pre-wrap break-words">{reply.body}</p>
|
|
168
|
+
</li>
|
|
169
|
+
{/each}
|
|
170
|
+
</ul>
|
|
171
|
+
{/if}
|
|
172
|
+
{#if (active || isDraft) && !thread.resolved}
|
|
173
|
+
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
|
|
174
|
+
<div class="flex flex-col gap-1" onclick={(e) => e.stopPropagation()}>
|
|
175
|
+
<!-- svelte-ignore a11y_autofocus -->
|
|
176
|
+
<textarea
|
|
177
|
+
class={textareaClass}
|
|
178
|
+
rows="2"
|
|
179
|
+
aria-label={isDraft ? "Comment" : "Reply"}
|
|
180
|
+
placeholder={isDraft ? "Add a comment…" : "Reply…"}
|
|
181
|
+
autofocus={isDraft}
|
|
182
|
+
value={drafts[thread.id] ?? ""}
|
|
183
|
+
oninput={(e) => (drafts[thread.id] = e.currentTarget.value)}
|
|
184
|
+
onkeydown={(e) => onTextareaKeydown(e, thread)}
|
|
185
|
+
></textarea>
|
|
186
|
+
<div class="flex justify-end gap-1">
|
|
187
|
+
{#if isDraft}
|
|
188
|
+
<button type="button" class={buttonClass} onclick={() => remove(thread)}>
|
|
189
|
+
Cancel
|
|
190
|
+
</button>
|
|
191
|
+
{/if}
|
|
192
|
+
<button
|
|
193
|
+
type="button"
|
|
194
|
+
class={primaryButtonClass}
|
|
195
|
+
disabled={!(drafts[thread.id] ?? "").trim()}
|
|
196
|
+
onclick={() => submit(thread)}
|
|
197
|
+
>
|
|
198
|
+
{isDraft ? "Comment" : "Reply"}
|
|
199
|
+
</button>
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
{/if}
|
|
203
|
+
{#if !isDraft}
|
|
204
|
+
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
|
|
205
|
+
<div class="flex justify-end gap-1" onclick={(e) => e.stopPropagation()}>
|
|
206
|
+
<button
|
|
207
|
+
type="button"
|
|
208
|
+
class={buttonClass}
|
|
209
|
+
onclick={() => setResolved(thread, !thread.resolved)}
|
|
210
|
+
>
|
|
211
|
+
{thread.resolved ? "Reopen" : "Resolve"}
|
|
212
|
+
</button>
|
|
213
|
+
<button
|
|
214
|
+
type="button"
|
|
215
|
+
class={`${buttonClass} hover:text-destructive`}
|
|
216
|
+
onclick={() => remove(thread)}
|
|
217
|
+
>
|
|
218
|
+
Delete
|
|
219
|
+
</button>
|
|
220
|
+
</div>
|
|
221
|
+
{/if}
|
|
222
|
+
</li>
|
|
223
|
+
{/each}
|
|
224
|
+
</ul>
|
|
225
|
+
{/if}
|
|
226
|
+
</aside>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Editor } from "@tiptap/core";
|
|
2
|
+
import { type CommentStore, type ReviewAuthor } from "@pixerate/editor";
|
|
3
|
+
interface Props {
|
|
4
|
+
editor?: Editor | null;
|
|
5
|
+
/** Defaults to the store of the editor's `Comments` extension. */
|
|
6
|
+
store?: CommentStore;
|
|
7
|
+
/** Author of replies. Defaults to the `Comments` extension's author. */
|
|
8
|
+
author?: ReviewAuthor;
|
|
9
|
+
/** Initially show resolved threads. */
|
|
10
|
+
showResolved?: boolean;
|
|
11
|
+
class?: string;
|
|
12
|
+
formatTime?: (timestamp: number) => string;
|
|
13
|
+
emptyMessage?: string;
|
|
14
|
+
}
|
|
15
|
+
declare const CommentsPanel: import("svelte").Component<Props, {}, "">;
|
|
16
|
+
type CommentsPanel = ReturnType<typeof CommentsPanel>;
|
|
17
|
+
export default CommentsPanel;
|
|
18
|
+
//# sourceMappingURL=CommentsPanel.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CommentsPanel.svelte.d.ts","sourceRoot":"","sources":["../../src/review/CommentsPanel.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAGH,KAAK,YAAY,EAEjB,KAAK,YAAY,EAClB,MAAM,kBAAkB,CAAC;AAI1B,UAAU,KAAK;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,kEAAkE;IAClE,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,wEAAwE;IACxE,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,uCAAuC;IACvC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAiLH,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Editor } from "@tiptap/core";
|
|
3
|
+
import { createTrackChanges, type SvelteTrackChanges } from "./review.svelte.js";
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
editor?: Editor | null;
|
|
7
|
+
class?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
editor = null,
|
|
12
|
+
class: className = "flex flex-wrap items-center gap-1 rounded-md border border-border bg-background p-1 text-sm",
|
|
13
|
+
}: Props = $props();
|
|
14
|
+
|
|
15
|
+
const buttonClass =
|
|
16
|
+
"rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
|
|
17
|
+
|
|
18
|
+
let review = $state.raw<SvelteTrackChanges>(createTrackChanges(null));
|
|
19
|
+
|
|
20
|
+
$effect(() => {
|
|
21
|
+
const r = createTrackChanges(editor);
|
|
22
|
+
review = r;
|
|
23
|
+
return () => r.destroy();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
let count = $derived(review.changes.length);
|
|
27
|
+
let current = $derived(review.currentChange);
|
|
28
|
+
let index = $derived(current ? review.changes.findIndex((c) => c.id === current.id) + 1 : 0);
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<div class={className} role="toolbar" aria-label="Review">
|
|
32
|
+
<button
|
|
33
|
+
type="button"
|
|
34
|
+
class={`${buttonClass} ${review.enabled ? "bg-primary/10 text-primary" : ""}`}
|
|
35
|
+
aria-pressed={review.enabled}
|
|
36
|
+
disabled={!editor}
|
|
37
|
+
onclick={() => review.toggle()}
|
|
38
|
+
>
|
|
39
|
+
{review.enabled ? "Tracking on" : "Track changes"}
|
|
40
|
+
</button>
|
|
41
|
+
<span class="mx-1 h-4 w-px bg-border" aria-hidden="true"></span>
|
|
42
|
+
<button
|
|
43
|
+
type="button"
|
|
44
|
+
class={buttonClass}
|
|
45
|
+
aria-label="Previous change"
|
|
46
|
+
disabled={count === 0}
|
|
47
|
+
onclick={() => review.previous()}
|
|
48
|
+
>
|
|
49
|
+
‹
|
|
50
|
+
</button>
|
|
51
|
+
<span class="min-w-[4rem] text-center text-xs text-muted-foreground" aria-live="polite">
|
|
52
|
+
{count === 0 ? "No changes" : current ? `${index} of ${count}` : `${count} changes`}
|
|
53
|
+
</span>
|
|
54
|
+
<button
|
|
55
|
+
type="button"
|
|
56
|
+
class={buttonClass}
|
|
57
|
+
aria-label="Next change"
|
|
58
|
+
disabled={count === 0}
|
|
59
|
+
onclick={() => review.next()}
|
|
60
|
+
>
|
|
61
|
+
›
|
|
62
|
+
</button>
|
|
63
|
+
<span class="mx-1 h-4 w-px bg-border" aria-hidden="true"></span>
|
|
64
|
+
<button
|
|
65
|
+
type="button"
|
|
66
|
+
class={buttonClass}
|
|
67
|
+
disabled={!current}
|
|
68
|
+
onclick={() => current && review.accept(current.id)}
|
|
69
|
+
>
|
|
70
|
+
Accept
|
|
71
|
+
</button>
|
|
72
|
+
<button
|
|
73
|
+
type="button"
|
|
74
|
+
class={buttonClass}
|
|
75
|
+
disabled={!current}
|
|
76
|
+
onclick={() => current && review.reject(current.id)}
|
|
77
|
+
>
|
|
78
|
+
Reject
|
|
79
|
+
</button>
|
|
80
|
+
<button type="button" class={buttonClass} disabled={count === 0} onclick={() => review.acceptAll()}>
|
|
81
|
+
Accept all
|
|
82
|
+
</button>
|
|
83
|
+
<button type="button" class={buttonClass} disabled={count === 0} onclick={() => review.rejectAll()}>
|
|
84
|
+
Reject all
|
|
85
|
+
</button>
|
|
86
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Editor } from "@tiptap/core";
|
|
2
|
+
interface Props {
|
|
3
|
+
editor?: Editor | null;
|
|
4
|
+
class?: string;
|
|
5
|
+
}
|
|
6
|
+
declare const ReviewToolbar: import("svelte").Component<Props, {}, "">;
|
|
7
|
+
type ReviewToolbar = ReturnType<typeof ReviewToolbar>;
|
|
8
|
+
export default ReviewToolbar;
|
|
9
|
+
//# sourceMappingURL=ReviewToolbar.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReviewToolbar.svelte.d.ts","sourceRoot":"","sources":["../../src/review/ReviewToolbar.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,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0DH,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ComponentProps } from "svelte";
|
|
2
|
+
import type CommentsPanelComponent from "./CommentsPanel.svelte";
|
|
3
|
+
import type ReviewToolbarComponent from "./ReviewToolbar.svelte";
|
|
4
|
+
import type CommentButtonComponent from "./CommentButton.svelte";
|
|
5
|
+
export { default as CommentsPanel } from "./CommentsPanel.svelte";
|
|
6
|
+
export { default as ReviewToolbar } from "./ReviewToolbar.svelte";
|
|
7
|
+
export { default as CommentButton } from "./CommentButton.svelte";
|
|
8
|
+
export * from "./review.svelte.js";
|
|
9
|
+
export type CommentsPanelProps = ComponentProps<typeof CommentsPanelComponent>;
|
|
10
|
+
export type ReviewToolbarProps = ComponentProps<typeof ReviewToolbarComponent>;
|
|
11
|
+
export type CommentButtonProps = ComponentProps<typeof CommentButtonComponent>;
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/review/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AAEjE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,cAAc,oBAAoB,CAAC;AAEnC,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Editor } from "@tiptap/core";
|
|
2
|
+
import { type CommentStore, type CommentStoreSnapshot, type CommentThread, type TrackChangesSnapshot, type TrackedChange } from "@pixerate/editor";
|
|
3
|
+
export declare const EMPTY_COMMENTS_SNAPSHOT: CommentStoreSnapshot;
|
|
4
|
+
export declare const EMPTY_TRACK_CHANGES_SNAPSHOT: TrackChangesSnapshot;
|
|
5
|
+
export declare function isCommentStore(value: unknown): value is CommentStore;
|
|
6
|
+
/** Resolves a comment store from a store or an editor using `Comments`. */
|
|
7
|
+
export declare function resolveCommentStore(source: Editor | CommentStore | null | undefined): CommentStore | null;
|
|
8
|
+
export interface SvelteComments {
|
|
9
|
+
readonly threads: readonly CommentThread[];
|
|
10
|
+
readonly activeThreadId: string | null;
|
|
11
|
+
readonly store: CommentStore | null;
|
|
12
|
+
subscribe(run: (value: CommentStoreSnapshot) => void): () => void;
|
|
13
|
+
destroy(): void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Reactive (runes) and Svelte-store-compatible view of a comment store. Pass
|
|
17
|
+
* the store or an editor using the `Comments` extension. Call `destroy()`
|
|
18
|
+
* when done (or create it inside a component, where it lives as long as the
|
|
19
|
+
* component).
|
|
20
|
+
*/
|
|
21
|
+
export declare function createComments(source: Editor | CommentStore | null | undefined): SvelteComments;
|
|
22
|
+
export interface SvelteTrackChanges extends TrackChangesSnapshot {
|
|
23
|
+
readonly currentChange: TrackedChange | null;
|
|
24
|
+
setEnabled(enabled: boolean): void;
|
|
25
|
+
toggle(): void;
|
|
26
|
+
accept(id: string): void;
|
|
27
|
+
reject(id: string): void;
|
|
28
|
+
acceptAll(): void;
|
|
29
|
+
rejectAll(): void;
|
|
30
|
+
next(): void;
|
|
31
|
+
previous(): void;
|
|
32
|
+
subscribe(run: (value: TrackChangesSnapshot) => void): () => void;
|
|
33
|
+
destroy(): void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Reactive (runes) and Svelte-store-compatible view of an editor's tracked
|
|
37
|
+
* changes (`TrackChanges` extension) with its commands.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createTrackChanges(editor: Editor | null | undefined): SvelteTrackChanges;
|
|
40
|
+
//# sourceMappingURL=review.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.svelte.d.ts","sourceRoot":"","sources":["../../src/review/review.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAE1B,eAAO,MAAM,uBAAuB,EAAE,oBAGZ,CAAC;AAE3B,eAAO,MAAM,4BAA4B,EAAE,oBAKjB,CAAC;AAE3B,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAMpE;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,GAAG,SAAS,GAC/C,YAAY,GAAG,IAAI,CAErB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAC3C,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAClE,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,cAAc,CA4B/F;AAED,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC9D,QAAQ,CAAC,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7C,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACnC,MAAM,IAAI,IAAI,CAAC;IACf,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,IAAI,IAAI,CAAC;IAClB,SAAS,IAAI,IAAI,CAAC;IAClB,IAAI,IAAI,IAAI,CAAC;IACb,QAAQ,IAAI,IAAI,CAAC;IACjB,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAClE,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,kBAAkB,CA+CxF"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { getCommentStore, getTrackChangesStore, } from "@pixerate/editor";
|
|
2
|
+
export const EMPTY_COMMENTS_SNAPSHOT = Object.freeze({
|
|
3
|
+
threads: [],
|
|
4
|
+
activeThreadId: null,
|
|
5
|
+
});
|
|
6
|
+
export const EMPTY_TRACK_CHANGES_SNAPSHOT = Object.freeze({
|
|
7
|
+
enabled: false,
|
|
8
|
+
author: { id: "anonymous", name: "Anonymous" },
|
|
9
|
+
changes: [],
|
|
10
|
+
currentChangeId: null,
|
|
11
|
+
});
|
|
12
|
+
export function isCommentStore(value) {
|
|
13
|
+
return (!!value &&
|
|
14
|
+
typeof value.getSnapshot === "function" &&
|
|
15
|
+
typeof value.createThread === "function");
|
|
16
|
+
}
|
|
17
|
+
/** Resolves a comment store from a store or an editor using `Comments`. */
|
|
18
|
+
export function resolveCommentStore(source) {
|
|
19
|
+
return isCommentStore(source) ? source : getCommentStore(source);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Reactive (runes) and Svelte-store-compatible view of a comment store. Pass
|
|
23
|
+
* the store or an editor using the `Comments` extension. Call `destroy()`
|
|
24
|
+
* when done (or create it inside a component, where it lives as long as the
|
|
25
|
+
* component).
|
|
26
|
+
*/
|
|
27
|
+
export function createComments(source) {
|
|
28
|
+
const store = resolveCommentStore(source);
|
|
29
|
+
let snapshot = $state.raw(store?.getSnapshot() ?? EMPTY_COMMENTS_SNAPSHOT);
|
|
30
|
+
const unsubscribe = store
|
|
31
|
+
? store.subscribe((value) => {
|
|
32
|
+
snapshot = value;
|
|
33
|
+
})
|
|
34
|
+
: () => { };
|
|
35
|
+
return {
|
|
36
|
+
get threads() {
|
|
37
|
+
return snapshot.threads;
|
|
38
|
+
},
|
|
39
|
+
get activeThreadId() {
|
|
40
|
+
return snapshot.activeThreadId;
|
|
41
|
+
},
|
|
42
|
+
get store() {
|
|
43
|
+
return store;
|
|
44
|
+
},
|
|
45
|
+
subscribe(run) {
|
|
46
|
+
if (!store) {
|
|
47
|
+
run(EMPTY_COMMENTS_SNAPSHOT);
|
|
48
|
+
return () => { };
|
|
49
|
+
}
|
|
50
|
+
return store.subscribe(run);
|
|
51
|
+
},
|
|
52
|
+
destroy: unsubscribe,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Reactive (runes) and Svelte-store-compatible view of an editor's tracked
|
|
57
|
+
* changes (`TrackChanges` extension) with its commands.
|
|
58
|
+
*/
|
|
59
|
+
export function createTrackChanges(editor) {
|
|
60
|
+
const store = getTrackChangesStore(editor ?? null);
|
|
61
|
+
let snapshot = $state.raw(store?.getSnapshot() ?? EMPTY_TRACK_CHANGES_SNAPSHOT);
|
|
62
|
+
const unsubscribe = store
|
|
63
|
+
? store.subscribe((value) => {
|
|
64
|
+
snapshot = value;
|
|
65
|
+
})
|
|
66
|
+
: () => { };
|
|
67
|
+
const run = (fn) => {
|
|
68
|
+
if (editor && !editor.isDestroyed)
|
|
69
|
+
fn(editor);
|
|
70
|
+
};
|
|
71
|
+
return {
|
|
72
|
+
get enabled() {
|
|
73
|
+
return snapshot.enabled;
|
|
74
|
+
},
|
|
75
|
+
get author() {
|
|
76
|
+
return snapshot.author;
|
|
77
|
+
},
|
|
78
|
+
get changes() {
|
|
79
|
+
return snapshot.changes;
|
|
80
|
+
},
|
|
81
|
+
get currentChangeId() {
|
|
82
|
+
return snapshot.currentChangeId;
|
|
83
|
+
},
|
|
84
|
+
get currentChange() {
|
|
85
|
+
return snapshot.changes.find((c) => c.id === snapshot.currentChangeId) ?? null;
|
|
86
|
+
},
|
|
87
|
+
setEnabled: (enabled) => run((e) => e.commands.setTrackChanges(enabled)),
|
|
88
|
+
toggle: () => run((e) => e.commands.toggleTrackChanges()),
|
|
89
|
+
accept: (id) => run((e) => e.commands.acceptChange(id)),
|
|
90
|
+
reject: (id) => run((e) => e.commands.rejectChange(id)),
|
|
91
|
+
acceptAll: () => run((e) => e.commands.acceptAllChanges()),
|
|
92
|
+
rejectAll: () => run((e) => e.commands.rejectAllChanges()),
|
|
93
|
+
next: () => run((e) => e.chain().focus().selectNextChange().run()),
|
|
94
|
+
previous: () => run((e) => e.chain().focus().selectPreviousChange().run()),
|
|
95
|
+
subscribe(runFn) {
|
|
96
|
+
if (!store) {
|
|
97
|
+
runFn(EMPTY_TRACK_CHANGES_SNAPSHOT);
|
|
98
|
+
return () => { };
|
|
99
|
+
}
|
|
100
|
+
return store.subscribe(runFn);
|
|
101
|
+
},
|
|
102
|
+
destroy: unsubscribe,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { indexToColName } from '@pixerate/editor';
|
|
3
3
|
import type { createReactiveSpreadsheet } from './spreadsheet.svelte.js';
|
|
4
|
+
import FormulaHints from './FormulaHints.svelte';
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
6
7
|
sheetState?: ReturnType<typeof createReactiveSpreadsheet>;
|
|
@@ -69,17 +70,22 @@
|
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
function handleInput(e: Event) {
|
|
72
|
-
|
|
73
|
+
setValue((e.target as HTMLInputElement).value);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function setValue(next: string) {
|
|
73
77
|
if (sheetState) {
|
|
74
|
-
sheetState.draftValue =
|
|
78
|
+
sheetState.draftValue = next;
|
|
75
79
|
if (sheetState.activeCell && !sheetState.editingCell) {
|
|
76
|
-
sheetState.startEditing(sheetState.activeCell.row, sheetState.activeCell.col,
|
|
80
|
+
sheetState.startEditing(sheetState.activeCell.row, sheetState.activeCell.col, next);
|
|
77
81
|
}
|
|
78
82
|
} else {
|
|
79
|
-
value =
|
|
83
|
+
value = next;
|
|
80
84
|
}
|
|
81
|
-
onChange?.(
|
|
85
|
+
onChange?.(next);
|
|
82
86
|
}
|
|
87
|
+
|
|
88
|
+
let inputEl = $state<HTMLInputElement | null>(null);
|
|
83
89
|
</script>
|
|
84
90
|
|
|
85
91
|
<div class="flex items-center gap-2 border-b border-border bg-muted/20 px-3 py-1.5 text-xs font-mono {className}">
|
|
@@ -94,8 +100,10 @@
|
|
|
94
100
|
class="flex-1 bg-transparent px-2 py-0.5 outline-none font-sans text-xs text-foreground placeholder:text-muted-foreground/60 focus:bg-background focus:ring-1 focus:ring-primary rounded"
|
|
95
101
|
placeholder="Enter a value or formula (e.g. =SUM(A1:A5))"
|
|
96
102
|
aria-label="Formula bar"
|
|
103
|
+
bind:this={inputEl}
|
|
97
104
|
value={effectiveValue}
|
|
98
105
|
oninput={handleInput}
|
|
99
106
|
onkeydown={handleKeyDown}
|
|
100
107
|
/>
|
|
108
|
+
<FormulaHints input={inputEl} value={effectiveValue} onAccept={setValue} />
|
|
101
109
|
</div>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormulaBar.svelte.d.ts","sourceRoot":"","sources":["../../src/spreadsheet/FormulaBar.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"FormulaBar.svelte.d.ts","sourceRoot":"","sources":["../../src/spreadsheet/FormulaBar.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAIvE,UAAU,KAAK;IACb,UAAU,CAAC,EAAE,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC;IAC1D,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA+FH,QAAA,MAAM,UAAU,gDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|