@pixerate/editor-svelte 0.8.1 → 0.10.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/dist/index.d.ts +100 -7
- package/dist/index.js +426 -203
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/createNavigationGuard.svelte.ts +97 -0
- package/src/history/createHistoryShortcuts.ts +95 -0
- package/src/history/history.svelte.ts +68 -0
- package/src/history/index.ts +2 -0
- package/src/index.d.ts +100 -7
- package/src/index.ts +30 -4
- package/src/navigationGuard.ts +82 -0
package/src/index.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { Component } from "svelte";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
Editor,
|
|
4
|
+
Content,
|
|
5
|
+
Extensions,
|
|
6
|
+
EditorOptions,
|
|
7
|
+
FocusPosition,
|
|
8
|
+
} from "@tiptap/core";
|
|
3
9
|
import type {
|
|
4
10
|
Template,
|
|
5
11
|
TemplateVersion,
|
|
@@ -96,8 +102,8 @@ import type {
|
|
|
96
102
|
CellCoordinate,
|
|
97
103
|
CellRange,
|
|
98
104
|
CellData,
|
|
99
|
-
SpreadsheetDataSource
|
|
100
|
-
} from
|
|
105
|
+
SpreadsheetDataSource,
|
|
106
|
+
} from "@pixerate/editor";
|
|
101
107
|
|
|
102
108
|
export interface SpreadsheetEditorProps {
|
|
103
109
|
sheetState: ReturnType<typeof createReactiveSpreadsheet>;
|
|
@@ -107,8 +113,16 @@ export interface SpreadsheetEditorProps {
|
|
|
107
113
|
class?: string;
|
|
108
114
|
customCellRenderer?:
|
|
109
115
|
| ((cell: CellData, col: SpreadsheetColumn, row: SpreadsheetRow) => any)
|
|
110
|
-
| ((args: {
|
|
111
|
-
|
|
116
|
+
| ((args: {
|
|
117
|
+
cell: CellData;
|
|
118
|
+
col: SpreadsheetColumn;
|
|
119
|
+
row: SpreadsheetRow;
|
|
120
|
+
}) => any)
|
|
121
|
+
| ((args: {
|
|
122
|
+
row: SpreadsheetRow;
|
|
123
|
+
col: SpreadsheetColumn;
|
|
124
|
+
cell: CellData;
|
|
125
|
+
}) => any);
|
|
112
126
|
onAddColumnClick?: () => void;
|
|
113
127
|
onColumnHeaderClick?: (col: SpreadsheetColumn) => void;
|
|
114
128
|
onColumnResize?: (colId: string, width: number) => void;
|
|
@@ -122,7 +136,9 @@ export interface FormulaBarProps {
|
|
|
122
136
|
export declare const SpreadsheetEditor: Component<SpreadsheetEditorProps>;
|
|
123
137
|
export declare const FormulaBar: Component<FormulaBarProps>;
|
|
124
138
|
|
|
125
|
-
export declare function createReactiveSpreadsheet(
|
|
139
|
+
export declare function createReactiveSpreadsheet(
|
|
140
|
+
options?: SpreadsheetControllerOptions,
|
|
141
|
+
): {
|
|
126
142
|
readonly document: SpreadsheetDocument;
|
|
127
143
|
readonly activeCell: CellCoordinate | null;
|
|
128
144
|
readonly selectedRange: CellRange | null;
|
|
@@ -136,7 +152,7 @@ export declare function createReactiveSpreadsheet(options?: SpreadsheetControlle
|
|
|
136
152
|
startEditing(row?: number, col?: number, initialVal?: string): void;
|
|
137
153
|
commitEditing(val?: string): void;
|
|
138
154
|
cancelEditing(): void;
|
|
139
|
-
moveCursor(dir:
|
|
155
|
+
moveCursor(dir: "up" | "down" | "left" | "right", extend?: boolean): void;
|
|
140
156
|
insertColumn(index: number, config?: Partial<SpreadsheetColumn>): void;
|
|
141
157
|
deleteColumn(colId: string): void;
|
|
142
158
|
insertRow(index: number, config?: Partial<SpreadsheetRow>): void;
|
|
@@ -152,3 +168,80 @@ export declare function createReactiveSpreadsheet(options?: SpreadsheetControlle
|
|
|
152
168
|
undo(): void;
|
|
153
169
|
redo(): void;
|
|
154
170
|
};
|
|
171
|
+
|
|
172
|
+
export interface NavigationGuardOptions {
|
|
173
|
+
isDirty: boolean;
|
|
174
|
+
enabled?: boolean;
|
|
175
|
+
onBlocked?: (url: string) => void;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export interface NavigationGuardActionReturn {
|
|
179
|
+
update(newOptions: NavigationGuardOptions): void;
|
|
180
|
+
destroy(): void;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export declare function navigationGuard(
|
|
184
|
+
node: HTMLElement,
|
|
185
|
+
options: NavigationGuardOptions,
|
|
186
|
+
): NavigationGuardActionReturn;
|
|
187
|
+
|
|
188
|
+
export interface CreateNavigationGuardOptions {
|
|
189
|
+
isDirty: boolean | (() => boolean);
|
|
190
|
+
enabled?: boolean | (() => boolean);
|
|
191
|
+
onNavigate?: (url: string) => void;
|
|
192
|
+
onBlocked?: (url: string) => void;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export interface NavigationGuardManager {
|
|
196
|
+
readonly showConfirm: boolean;
|
|
197
|
+
setShowConfirm(show: boolean): void;
|
|
198
|
+
readonly pendingUrl: string | null;
|
|
199
|
+
intercept(url: string): boolean;
|
|
200
|
+
confirmLeave(): void;
|
|
201
|
+
cancelLeave(): void;
|
|
202
|
+
destroy(): void;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export declare function createNavigationGuard(
|
|
206
|
+
options: CreateNavigationGuardOptions,
|
|
207
|
+
): NavigationGuardManager;
|
|
208
|
+
|
|
209
|
+
export interface SvelteHistory extends HistoryState {
|
|
210
|
+
readonly manager: HistoryManager;
|
|
211
|
+
undo(): boolean;
|
|
212
|
+
redo(): boolean;
|
|
213
|
+
clear(): void;
|
|
214
|
+
execute(command: Command): void;
|
|
215
|
+
executeMerged(command: Command, options?: { windowMs?: number }): void;
|
|
216
|
+
batch(name: string, fn: () => void): void;
|
|
217
|
+
subscribe(run: (value: HistoryState) => void): () => void;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export declare function createHistory(
|
|
221
|
+
managerOrOptions?: HistoryManager | HistoryManagerOptions,
|
|
222
|
+
): SvelteHistory;
|
|
223
|
+
|
|
224
|
+
export interface HistoryShortcutsOptions {
|
|
225
|
+
enabled?: boolean;
|
|
226
|
+
target?: Window | HTMLElement | null;
|
|
227
|
+
ignoreEditableElements?: boolean;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export declare function createHistoryShortcuts(
|
|
231
|
+
manager: HistoryManager,
|
|
232
|
+
options?: HistoryShortcutsOptions,
|
|
233
|
+
): { destroy: () => void };
|
|
234
|
+
|
|
235
|
+
export {
|
|
236
|
+
DirtyTracker,
|
|
237
|
+
createDirtyTracker,
|
|
238
|
+
defaultIsEqual,
|
|
239
|
+
HistoryManager,
|
|
240
|
+
createHistoryManager,
|
|
241
|
+
} from "@pixerate/editor";
|
|
242
|
+
export type {
|
|
243
|
+
DirtyTrackerOptions,
|
|
244
|
+
Command,
|
|
245
|
+
HistoryState,
|
|
246
|
+
HistoryManagerOptions,
|
|
247
|
+
} from "@pixerate/editor";
|
package/src/index.ts
CHANGED
|
@@ -1,12 +1,35 @@
|
|
|
1
1
|
import type { Component } from "svelte";
|
|
2
2
|
import type { Editor, Content, Extensions, FocusPosition } from "@tiptap/core";
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
Template,
|
|
5
|
+
ColorGradient,
|
|
6
|
+
RichTextPresetOptions,
|
|
7
|
+
MarkdownOptions,
|
|
8
|
+
ImageOptions,
|
|
9
|
+
} from "@pixerate/editor";
|
|
4
10
|
|
|
5
11
|
import EditableTextNodeEditorComponent from "./EditableTextNodeEditor.svelte";
|
|
6
12
|
import BubbleMenuComponent from "./BubbleMenu.svelte";
|
|
7
13
|
import TemplateRendererComponent from "./TemplateRenderer.svelte";
|
|
8
14
|
|
|
9
15
|
export * from "./editor.svelte";
|
|
16
|
+
export * from "./navigationGuard";
|
|
17
|
+
export * from "./createNavigationGuard.svelte";
|
|
18
|
+
export * from "./history";
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
DirtyTracker,
|
|
22
|
+
createDirtyTracker,
|
|
23
|
+
defaultIsEqual,
|
|
24
|
+
HistoryManager,
|
|
25
|
+
createHistoryManager,
|
|
26
|
+
} from "@pixerate/editor";
|
|
27
|
+
export type {
|
|
28
|
+
DirtyTrackerOptions,
|
|
29
|
+
Command,
|
|
30
|
+
HistoryState,
|
|
31
|
+
HistoryManagerOptions,
|
|
32
|
+
} from "@pixerate/editor";
|
|
10
33
|
|
|
11
34
|
export interface EditableTextNodeEditorProps {
|
|
12
35
|
class?: string;
|
|
@@ -45,9 +68,12 @@ export interface TemplateRendererProps {
|
|
|
45
68
|
onVariableClick?: (variableName: string) => void;
|
|
46
69
|
}
|
|
47
70
|
|
|
48
|
-
export const EditableTextNodeEditor =
|
|
49
|
-
|
|
50
|
-
export const
|
|
71
|
+
export const EditableTextNodeEditor =
|
|
72
|
+
EditableTextNodeEditorComponent as unknown as Component<EditableTextNodeEditorProps>;
|
|
73
|
+
export const BubbleMenu =
|
|
74
|
+
BubbleMenuComponent as unknown as Component<BubbleMenuProps>;
|
|
75
|
+
export const TemplateRenderer =
|
|
76
|
+
TemplateRendererComponent as unknown as Component<TemplateRendererProps>;
|
|
51
77
|
|
|
52
78
|
export type {
|
|
53
79
|
Template,
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export interface NavigationGuardOptions {
|
|
2
|
+
/** Whether the current form or editor has unsaved changes */
|
|
3
|
+
isDirty: boolean;
|
|
4
|
+
/** Whether guarding is enabled (defaults to true) */
|
|
5
|
+
enabled?: boolean;
|
|
6
|
+
/** Callback fired when an internal navigation attempt is intercepted */
|
|
7
|
+
onBlocked?: (url: string) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface NavigationGuardActionReturn {
|
|
11
|
+
update(newOptions: NavigationGuardOptions): void;
|
|
12
|
+
destroy(): void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Svelte action to guard against navigation when there are unsaved changes.
|
|
17
|
+
* Attaches beforeunload to window and intercepts internal anchor clicks on the element.
|
|
18
|
+
*
|
|
19
|
+
* Usage:
|
|
20
|
+
* <div use:navigationGuard={{ isDirty, onBlocked: (url) => { pendingUrl = url; showConfirm = true; } }}>
|
|
21
|
+
*/
|
|
22
|
+
export function navigationGuard(
|
|
23
|
+
node: HTMLElement,
|
|
24
|
+
options: NavigationGuardOptions,
|
|
25
|
+
): NavigationGuardActionReturn {
|
|
26
|
+
let isDirty = options.isDirty;
|
|
27
|
+
let enabled = options.enabled ?? true;
|
|
28
|
+
let onBlocked = options.onBlocked;
|
|
29
|
+
|
|
30
|
+
function handleBeforeUnload(e: BeforeUnloadEvent) {
|
|
31
|
+
if (!enabled || !isDirty) return;
|
|
32
|
+
e.preventDefault();
|
|
33
|
+
e.returnValue = "";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function handleClick(e: MouseEvent) {
|
|
37
|
+
if (!enabled || !isDirty) return;
|
|
38
|
+
|
|
39
|
+
const target = e.target as HTMLElement | null;
|
|
40
|
+
const anchor = target?.closest?.("a");
|
|
41
|
+
if (!anchor) return;
|
|
42
|
+
if (anchor.target === "_blank") return;
|
|
43
|
+
|
|
44
|
+
// Check if link is internal
|
|
45
|
+
if (typeof window !== "undefined") {
|
|
46
|
+
const isInternal = anchor.host === window.location.host;
|
|
47
|
+
if (!isInternal) return;
|
|
48
|
+
|
|
49
|
+
if (
|
|
50
|
+
anchor.pathname === window.location.pathname &&
|
|
51
|
+
anchor.search === window.location.search
|
|
52
|
+
) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
e.preventDefault();
|
|
58
|
+
e.stopPropagation();
|
|
59
|
+
|
|
60
|
+
const href = anchor.href;
|
|
61
|
+
onBlocked?.(href);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (typeof window !== "undefined") {
|
|
65
|
+
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
66
|
+
}
|
|
67
|
+
node.addEventListener("click", handleClick, { capture: true });
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
update(newOptions: NavigationGuardOptions) {
|
|
71
|
+
isDirty = newOptions.isDirty;
|
|
72
|
+
enabled = newOptions.enabled ?? true;
|
|
73
|
+
onBlocked = newOptions.onBlocked;
|
|
74
|
+
},
|
|
75
|
+
destroy() {
|
|
76
|
+
if (typeof window !== "undefined") {
|
|
77
|
+
window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
78
|
+
}
|
|
79
|
+
node.removeEventListener("click", handleClick, { capture: true });
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|