@pixerate/editor-react 0.3.13 → 0.5.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.cjs +295 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +98 -5
- package/dist/index.d.ts +98 -5
- package/dist/index.js +286 -48
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as _tiptap_core from '@tiptap/core';
|
|
2
2
|
import { Editor } from '@tiptap/core';
|
|
3
3
|
import * as _pixerate_editor from '@pixerate/editor';
|
|
4
|
-
import { Template, ColorGradient, RichTextPresetOptions, SpreadsheetControllerOptions, SpreadsheetDocument, CellCoordinate, CellRange, SpreadsheetController, SpreadsheetColumn, SpreadsheetRow, SpreadsheetDataSource, CellData } from '@pixerate/editor';
|
|
5
|
-
export { ColorGradient, RichTextPresetOptions, Template, TemplateVersion, Token, TokenType } from '@pixerate/editor';
|
|
4
|
+
import { Template, ColorGradient, RichTextPresetOptions, HistoryState, HistoryManager, Command, HistoryManagerOptions, SpreadsheetControllerOptions, SpreadsheetDocument, CellCoordinate, CellRange, SpreadsheetController, SpreadsheetColumn, SpreadsheetRow, SpreadsheetDataSource, CellData } from '@pixerate/editor';
|
|
5
|
+
export { ColorGradient, Command, DirtyTracker, DirtyTrackerOptions, HistoryManager, HistoryManagerOptions, HistoryState, RichTextPresetOptions, Template, TemplateVersion, Token, TokenType, createDirtyTracker, createHistoryManager, defaultIsEqual } from '@pixerate/editor';
|
|
6
6
|
import { UseEditorOptions, EditorContentProps as EditorContentProps$1 } from '@tiptap/react';
|
|
7
|
-
import * as React from 'react';
|
|
7
|
+
import * as React$1 from 'react';
|
|
8
8
|
import React__default from 'react';
|
|
9
9
|
import { BubbleMenuPluginProps } from '@tiptap/extension-bubble-menu';
|
|
10
10
|
|
|
@@ -60,6 +60,99 @@ interface UseRichEditorProps extends UseEditorOptions {
|
|
|
60
60
|
*/
|
|
61
61
|
declare function useEditor(options?: UseRichEditorProps): _tiptap_core.Editor | null;
|
|
62
62
|
|
|
63
|
+
interface UseNavigationGuardOptions {
|
|
64
|
+
/** Whether the current form or editor has unsaved changes */
|
|
65
|
+
isDirty: boolean;
|
|
66
|
+
/** Whether guarding is enabled (defaults to true) */
|
|
67
|
+
enabled?: boolean;
|
|
68
|
+
/** Custom navigation function (e.g. router.push from next/navigation or react-router) */
|
|
69
|
+
onNavigate?: (url: string) => void;
|
|
70
|
+
/** Optional callback fired when an internal navigation attempt is intercepted */
|
|
71
|
+
onBlocked?: (url: string) => void;
|
|
72
|
+
}
|
|
73
|
+
interface UseNavigationGuardReturn {
|
|
74
|
+
/** Whether the unsaved changes confirmation dialog should be displayed */
|
|
75
|
+
showConfirm: boolean;
|
|
76
|
+
/** Setter to manually control the dialog visibility */
|
|
77
|
+
setShowConfirm: (show: boolean) => void;
|
|
78
|
+
/** The target URL that the user attempted to navigate to */
|
|
79
|
+
pendingUrl: string | null;
|
|
80
|
+
/** Proceeds with the blocked navigation and closes the dialog */
|
|
81
|
+
confirmLeave: () => void;
|
|
82
|
+
/** Cancels the navigation attempt and keeps the user on the current page */
|
|
83
|
+
cancelLeave: () => void;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Hook to guard against navigation when there are unsaved changes.
|
|
87
|
+
* Intercepts both external unloads (tab closing/refreshing) and internal link clicks.
|
|
88
|
+
*/
|
|
89
|
+
declare function useNavigationGuard({ isDirty, enabled, onNavigate, onBlocked, }: UseNavigationGuardOptions): UseNavigationGuardReturn;
|
|
90
|
+
|
|
91
|
+
interface UseDismissGuardOptions {
|
|
92
|
+
/** Whether there are unsaved changes */
|
|
93
|
+
isDirty: boolean;
|
|
94
|
+
/** Whether the dismissal guard is enabled (defaults to true) */
|
|
95
|
+
enabled?: boolean;
|
|
96
|
+
/** Callback fired when dismissal is confirmed or when clean dismissal occurs */
|
|
97
|
+
onDismiss?: () => void;
|
|
98
|
+
}
|
|
99
|
+
interface UseDismissGuardReturn {
|
|
100
|
+
/** Whether the discard confirmation modal should be shown */
|
|
101
|
+
showConfirm: boolean;
|
|
102
|
+
/** Manually update confirmation modal visibility */
|
|
103
|
+
setShowConfirm: (show: boolean) => void;
|
|
104
|
+
/** Request dismissal - checks isDirty and shows confirm or executes onDismiss */
|
|
105
|
+
requestDismiss: () => void;
|
|
106
|
+
/** Confirm discarding changes and dismiss */
|
|
107
|
+
confirmDismiss: () => void;
|
|
108
|
+
/** Cancel discarding and resume editing */
|
|
109
|
+
cancelDismiss: () => void;
|
|
110
|
+
/** Helper keydown handler intercepting Escape key */
|
|
111
|
+
handleKeyDown: (event: React.KeyboardEvent | KeyboardEvent) => boolean;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Hook to guard against closing or exiting an editor/dialog with uncommitted changes.
|
|
115
|
+
*/
|
|
116
|
+
declare function useDismissGuard({ isDirty, enabled, onDismiss, }: UseDismissGuardOptions): UseDismissGuardReturn;
|
|
117
|
+
|
|
118
|
+
interface UseHistoryResult extends HistoryState {
|
|
119
|
+
manager: HistoryManager;
|
|
120
|
+
undo: () => boolean;
|
|
121
|
+
redo: () => boolean;
|
|
122
|
+
clear: () => void;
|
|
123
|
+
execute: (command: Command) => void;
|
|
124
|
+
executeMerged: (command: Command, options?: {
|
|
125
|
+
windowMs?: number;
|
|
126
|
+
}) => void;
|
|
127
|
+
batch: (name: string, fn: () => void) => void;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* React hook that subscribes to a HistoryManager instance.
|
|
131
|
+
* Accepts an existing HistoryManager or config options to create an instance.
|
|
132
|
+
*/
|
|
133
|
+
declare function useHistory(managerOrOptions?: HistoryManager | HistoryManagerOptions): UseHistoryResult;
|
|
134
|
+
|
|
135
|
+
interface HistoryShortcutsOptions {
|
|
136
|
+
/**
|
|
137
|
+
* Whether the keyboard shortcuts are enabled. Defaults to true.
|
|
138
|
+
*/
|
|
139
|
+
enabled?: boolean;
|
|
140
|
+
/**
|
|
141
|
+
* Target element or window to listen on. Defaults to window.
|
|
142
|
+
*/
|
|
143
|
+
target?: Window | HTMLElement | null;
|
|
144
|
+
/**
|
|
145
|
+
* When true (default), shortcuts will not trigger if an <input>, <textarea>,
|
|
146
|
+
* or [contenteditable] element is currently active / focused.
|
|
147
|
+
*/
|
|
148
|
+
ignoreEditableElements?: boolean;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Attaches keyboard listeners for Undo (Mod+Z) and Redo (Mod+Shift+Z / Mod+Y).
|
|
152
|
+
* Automatically guards against active text inputs and contenteditable editors.
|
|
153
|
+
*/
|
|
154
|
+
declare function useHistoryShortcuts(manager: HistoryManager, options?: HistoryShortcutsOptions): void;
|
|
155
|
+
|
|
63
156
|
interface EditorContentProps extends EditorContentProps$1 {
|
|
64
157
|
className?: string;
|
|
65
158
|
}
|
|
@@ -100,7 +193,7 @@ declare function useSpreadsheetEditor(options?: SpreadsheetControllerOptions): {
|
|
|
100
193
|
selectedRange: CellRange | null;
|
|
101
194
|
editingCell: CellCoordinate | null;
|
|
102
195
|
draftValue: string;
|
|
103
|
-
setDraftValue: React.Dispatch<React.SetStateAction<string>>;
|
|
196
|
+
setDraftValue: React$1.Dispatch<React$1.SetStateAction<string>>;
|
|
104
197
|
controller: SpreadsheetController;
|
|
105
198
|
getCell: (rowId: string, colId: string) => _pixerate_editor.CellData;
|
|
106
199
|
setCellValue: (rowId: string, colId: string, raw: string) => void;
|
|
@@ -141,4 +234,4 @@ interface SpreadsheetEditorProps {
|
|
|
141
234
|
}
|
|
142
235
|
declare const SpreadsheetEditor: React__default.FC<SpreadsheetEditorProps>;
|
|
143
236
|
|
|
144
|
-
export { BubbleMenu, type BubbleMenuProps, EditorContent, type EditorContentProps, SpreadsheetEditor, type SpreadsheetEditorProps, TemplateRenderer, type TemplateRendererProps, type UsePromptEditorProps, type UseRichEditorProps, useEditor, usePromptEditor, useSpreadsheetEditor };
|
|
237
|
+
export { BubbleMenu, type BubbleMenuProps, EditorContent, type EditorContentProps, type HistoryShortcutsOptions, SpreadsheetEditor, type SpreadsheetEditorProps, TemplateRenderer, type TemplateRendererProps, type UseDismissGuardOptions, type UseDismissGuardReturn, type UseHistoryResult, type UseNavigationGuardOptions, type UseNavigationGuardReturn, type UsePromptEditorProps, type UseRichEditorProps, useDismissGuard, useEditor, useHistory, useHistoryShortcuts, useNavigationGuard, usePromptEditor, useSpreadsheetEditor };
|
package/dist/index.js
CHANGED
|
@@ -227,6 +227,226 @@ function useEditor2(options = {}) {
|
|
|
227
227
|
});
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
+
// src/hooks/useNavigationGuard.ts
|
|
231
|
+
import { useState, useEffect as useEffect2, useCallback, useRef as useRef2 } from "react";
|
|
232
|
+
function useNavigationGuard({
|
|
233
|
+
isDirty,
|
|
234
|
+
enabled = true,
|
|
235
|
+
onNavigate,
|
|
236
|
+
onBlocked
|
|
237
|
+
}) {
|
|
238
|
+
const [showConfirm, setShowConfirm] = useState(false);
|
|
239
|
+
const [pendingUrl, setPendingUrl] = useState(null);
|
|
240
|
+
const onNavigateRef = useRef2(onNavigate);
|
|
241
|
+
onNavigateRef.current = onNavigate;
|
|
242
|
+
const onBlockedRef = useRef2(onBlocked);
|
|
243
|
+
onBlockedRef.current = onBlocked;
|
|
244
|
+
useEffect2(() => {
|
|
245
|
+
if (typeof window === "undefined") return;
|
|
246
|
+
if (!enabled || !isDirty) return;
|
|
247
|
+
const handleBeforeUnload = (e) => {
|
|
248
|
+
e.preventDefault();
|
|
249
|
+
e.returnValue = "";
|
|
250
|
+
};
|
|
251
|
+
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
252
|
+
return () => {
|
|
253
|
+
window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
254
|
+
};
|
|
255
|
+
}, [enabled, isDirty]);
|
|
256
|
+
useEffect2(() => {
|
|
257
|
+
if (typeof document === "undefined" || typeof window === "undefined")
|
|
258
|
+
return;
|
|
259
|
+
if (!enabled || !isDirty) return;
|
|
260
|
+
const handleClick = (e) => {
|
|
261
|
+
const target = e.target;
|
|
262
|
+
const anchor = target?.closest?.("a");
|
|
263
|
+
if (!anchor) return;
|
|
264
|
+
if (anchor.target === "_blank") return;
|
|
265
|
+
const isInternal = anchor.host === window.location.host;
|
|
266
|
+
if (!isInternal) return;
|
|
267
|
+
if (anchor.pathname === window.location.pathname && anchor.search === window.location.search) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
e.preventDefault();
|
|
271
|
+
e.stopPropagation();
|
|
272
|
+
const href = anchor.href;
|
|
273
|
+
setPendingUrl(href);
|
|
274
|
+
setShowConfirm(true);
|
|
275
|
+
onBlockedRef.current?.(href);
|
|
276
|
+
};
|
|
277
|
+
document.addEventListener("click", handleClick, { capture: true });
|
|
278
|
+
return () => {
|
|
279
|
+
document.removeEventListener("click", handleClick, { capture: true });
|
|
280
|
+
};
|
|
281
|
+
}, [enabled, isDirty]);
|
|
282
|
+
const confirmLeave = useCallback(() => {
|
|
283
|
+
setShowConfirm(false);
|
|
284
|
+
if (pendingUrl) {
|
|
285
|
+
if (onNavigateRef.current) {
|
|
286
|
+
onNavigateRef.current(pendingUrl);
|
|
287
|
+
} else if (typeof window !== "undefined") {
|
|
288
|
+
window.location.href = pendingUrl;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}, [pendingUrl]);
|
|
292
|
+
const cancelLeave = useCallback(() => {
|
|
293
|
+
setShowConfirm(false);
|
|
294
|
+
setPendingUrl(null);
|
|
295
|
+
}, []);
|
|
296
|
+
return {
|
|
297
|
+
showConfirm,
|
|
298
|
+
setShowConfirm,
|
|
299
|
+
pendingUrl,
|
|
300
|
+
confirmLeave,
|
|
301
|
+
cancelLeave
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// src/hooks/useDismissGuard.ts
|
|
306
|
+
import { useState as useState2, useCallback as useCallback2, useRef as useRef3 } from "react";
|
|
307
|
+
function useDismissGuard({
|
|
308
|
+
isDirty,
|
|
309
|
+
enabled = true,
|
|
310
|
+
onDismiss
|
|
311
|
+
}) {
|
|
312
|
+
const [showConfirm, setShowConfirm] = useState2(false);
|
|
313
|
+
const onDismissRef = useRef3(onDismiss);
|
|
314
|
+
onDismissRef.current = onDismiss;
|
|
315
|
+
const requestDismiss = useCallback2(() => {
|
|
316
|
+
if (enabled && isDirty) {
|
|
317
|
+
setShowConfirm(true);
|
|
318
|
+
} else {
|
|
319
|
+
onDismissRef.current?.();
|
|
320
|
+
}
|
|
321
|
+
}, [enabled, isDirty]);
|
|
322
|
+
const confirmDismiss = useCallback2(() => {
|
|
323
|
+
setShowConfirm(false);
|
|
324
|
+
onDismissRef.current?.();
|
|
325
|
+
}, []);
|
|
326
|
+
const cancelDismiss = useCallback2(() => {
|
|
327
|
+
setShowConfirm(false);
|
|
328
|
+
}, []);
|
|
329
|
+
const handleKeyDown = useCallback2(
|
|
330
|
+
(event) => {
|
|
331
|
+
if (event.key === "Escape") {
|
|
332
|
+
if (event.defaultPrevented) return false;
|
|
333
|
+
event.preventDefault();
|
|
334
|
+
requestDismiss();
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
return false;
|
|
338
|
+
},
|
|
339
|
+
[requestDismiss]
|
|
340
|
+
);
|
|
341
|
+
return {
|
|
342
|
+
showConfirm,
|
|
343
|
+
setShowConfirm,
|
|
344
|
+
requestDismiss,
|
|
345
|
+
confirmDismiss,
|
|
346
|
+
cancelDismiss,
|
|
347
|
+
handleKeyDown
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// src/hooks/useHistory.ts
|
|
352
|
+
import { useSyncExternalStore, useMemo as useMemo2, useCallback as useCallback3 } from "react";
|
|
353
|
+
import {
|
|
354
|
+
HistoryManager,
|
|
355
|
+
createHistoryManager
|
|
356
|
+
} from "@pixerate/editor";
|
|
357
|
+
function useHistory(managerOrOptions) {
|
|
358
|
+
const manager = useMemo2(() => {
|
|
359
|
+
if (managerOrOptions instanceof HistoryManager) {
|
|
360
|
+
return managerOrOptions;
|
|
361
|
+
}
|
|
362
|
+
return createHistoryManager(managerOrOptions);
|
|
363
|
+
}, [managerOrOptions]);
|
|
364
|
+
const state = useSyncExternalStore(
|
|
365
|
+
useCallback3(
|
|
366
|
+
(onStoreChange) => manager.subscribe(onStoreChange),
|
|
367
|
+
[manager]
|
|
368
|
+
),
|
|
369
|
+
() => manager.getState(),
|
|
370
|
+
() => manager.getState()
|
|
371
|
+
);
|
|
372
|
+
const undo = useCallback3(() => manager.undo(), [manager]);
|
|
373
|
+
const redo = useCallback3(() => manager.redo(), [manager]);
|
|
374
|
+
const clear = useCallback3(() => manager.clear(), [manager]);
|
|
375
|
+
const execute = useCallback3(
|
|
376
|
+
(cmd) => manager.execute(cmd),
|
|
377
|
+
[manager]
|
|
378
|
+
);
|
|
379
|
+
const executeMerged = useCallback3(
|
|
380
|
+
(cmd, opts) => manager.executeMerged(cmd, opts),
|
|
381
|
+
[manager]
|
|
382
|
+
);
|
|
383
|
+
const batch = useCallback3(
|
|
384
|
+
(name, fn) => manager.batch(name, fn),
|
|
385
|
+
[manager]
|
|
386
|
+
);
|
|
387
|
+
return {
|
|
388
|
+
...state,
|
|
389
|
+
manager,
|
|
390
|
+
undo,
|
|
391
|
+
redo,
|
|
392
|
+
clear,
|
|
393
|
+
execute,
|
|
394
|
+
executeMerged,
|
|
395
|
+
batch
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// src/hooks/useHistoryShortcuts.ts
|
|
400
|
+
import { useEffect as useEffect3 } from "react";
|
|
401
|
+
function useHistoryShortcuts(manager, options = {}) {
|
|
402
|
+
const {
|
|
403
|
+
enabled = true,
|
|
404
|
+
target,
|
|
405
|
+
ignoreEditableElements = true
|
|
406
|
+
} = options;
|
|
407
|
+
useEffect3(() => {
|
|
408
|
+
if (!enabled) return;
|
|
409
|
+
const eventTarget = target ?? (typeof window !== "undefined" ? window : null);
|
|
410
|
+
if (!eventTarget) return;
|
|
411
|
+
const handleKeyDown = (event) => {
|
|
412
|
+
const e = event;
|
|
413
|
+
const isMac = typeof navigator !== "undefined" && /Mac|iPod|iPhone|iPad/.test(navigator.platform || navigator.userAgent);
|
|
414
|
+
const modifier = isMac ? e.metaKey : e.ctrlKey;
|
|
415
|
+
if (!modifier) return;
|
|
416
|
+
if (ignoreEditableElements && typeof document !== "undefined") {
|
|
417
|
+
const targetEl = e.target || document.activeElement;
|
|
418
|
+
if (targetEl && targetEl.tagName) {
|
|
419
|
+
const tagName = targetEl.tagName.toLowerCase();
|
|
420
|
+
const isInput = tagName === "input" || tagName === "textarea";
|
|
421
|
+
const isContentEditable = targetEl.isContentEditable || targetEl.getAttribute?.("contenteditable") === "true";
|
|
422
|
+
if (isInput || isContentEditable) {
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
const key = e.key.toLowerCase();
|
|
428
|
+
if (key === "z" && !e.shiftKey) {
|
|
429
|
+
if (manager.getState().canUndo) {
|
|
430
|
+
e.preventDefault();
|
|
431
|
+
manager.undo();
|
|
432
|
+
}
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
const isRedoKey = key === "z" && e.shiftKey || !isMac && key === "y" && !e.shiftKey;
|
|
436
|
+
if (isRedoKey) {
|
|
437
|
+
if (manager.getState().canRedo) {
|
|
438
|
+
e.preventDefault();
|
|
439
|
+
manager.redo();
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
eventTarget.addEventListener("keydown", handleKeyDown);
|
|
444
|
+
return () => {
|
|
445
|
+
eventTarget.removeEventListener("keydown", handleKeyDown);
|
|
446
|
+
};
|
|
447
|
+
}, [manager, enabled, target, ignoreEditableElements]);
|
|
448
|
+
}
|
|
449
|
+
|
|
230
450
|
// src/components/EditorContent.tsx
|
|
231
451
|
import {
|
|
232
452
|
EditorContent as TipTapEditorContent
|
|
@@ -241,7 +461,7 @@ var EditorContent = ({
|
|
|
241
461
|
};
|
|
242
462
|
|
|
243
463
|
// src/components/BubbleMenu.tsx
|
|
244
|
-
import { useEffect as
|
|
464
|
+
import { useEffect as useEffect4, useRef as useRef4, useState as useState3 } from "react";
|
|
245
465
|
import { createPortal } from "react-dom";
|
|
246
466
|
import {
|
|
247
467
|
BubbleMenuPlugin
|
|
@@ -255,12 +475,12 @@ var BubbleMenu = ({
|
|
|
255
475
|
pluginKey = "bubbleMenu",
|
|
256
476
|
updateDelay
|
|
257
477
|
}) => {
|
|
258
|
-
const menuEl =
|
|
259
|
-
const [mounted, setMounted] =
|
|
478
|
+
const menuEl = useRef4(null);
|
|
479
|
+
const [mounted, setMounted] = useState3(false);
|
|
260
480
|
if (!menuEl.current && typeof document !== "undefined") {
|
|
261
481
|
menuEl.current = document.createElement("div");
|
|
262
482
|
}
|
|
263
|
-
|
|
483
|
+
useEffect4(() => {
|
|
264
484
|
if (!editor || !menuEl.current || editor.isDestroyed) {
|
|
265
485
|
return;
|
|
266
486
|
}
|
|
@@ -291,7 +511,7 @@ var BubbleMenu = ({
|
|
|
291
511
|
};
|
|
292
512
|
|
|
293
513
|
// src/components/TemplateRenderer.tsx
|
|
294
|
-
import { useMemo as
|
|
514
|
+
import { useMemo as useMemo3 } from "react";
|
|
295
515
|
import {
|
|
296
516
|
tokenizePrompt,
|
|
297
517
|
resolveTemplates
|
|
@@ -306,11 +526,11 @@ var TemplateRenderer = ({
|
|
|
306
526
|
onTemplateClick,
|
|
307
527
|
onVariableClick
|
|
308
528
|
}) => {
|
|
309
|
-
const displayText =
|
|
529
|
+
const displayText = useMemo3(() => {
|
|
310
530
|
if (!resolve || templates.length === 0) return content;
|
|
311
531
|
return resolveTemplates(content, templates);
|
|
312
532
|
}, [content, templates, resolve]);
|
|
313
|
-
const tokens =
|
|
533
|
+
const tokens = useMemo3(() => {
|
|
314
534
|
return tokenizePrompt(displayText);
|
|
315
535
|
}, [displayText]);
|
|
316
536
|
return /* @__PURE__ */ jsx2("div", { className, children: tokens.map((token, index) => {
|
|
@@ -362,13 +582,22 @@ var TemplateRenderer = ({
|
|
|
362
582
|
}) });
|
|
363
583
|
};
|
|
364
584
|
|
|
585
|
+
// src/index.ts
|
|
586
|
+
import {
|
|
587
|
+
DirtyTracker,
|
|
588
|
+
createDirtyTracker,
|
|
589
|
+
defaultIsEqual,
|
|
590
|
+
HistoryManager as HistoryManager2,
|
|
591
|
+
createHistoryManager as createHistoryManager2
|
|
592
|
+
} from "@pixerate/editor";
|
|
593
|
+
|
|
365
594
|
// src/spreadsheet/useSpreadsheetEditor.ts
|
|
366
|
-
import { useState as
|
|
595
|
+
import { useState as useState4, useMemo as useMemo4, useCallback as useCallback4 } from "react";
|
|
367
596
|
import {
|
|
368
597
|
SpreadsheetController
|
|
369
598
|
} from "@pixerate/editor";
|
|
370
599
|
function useSpreadsheetEditor(options = {}) {
|
|
371
|
-
const [doc, setDoc] =
|
|
600
|
+
const [doc, setDoc] = useState4(() => ({
|
|
372
601
|
id: options.document?.id || `sheet_${Date.now()}`,
|
|
373
602
|
name: options.document?.name || "Sheet 1",
|
|
374
603
|
columns: options.document?.columns || [],
|
|
@@ -377,11 +606,11 @@ function useSpreadsheetEditor(options = {}) {
|
|
|
377
606
|
createdAt: options.document?.createdAt || Date.now(),
|
|
378
607
|
updatedAt: options.document?.updatedAt || Date.now()
|
|
379
608
|
}));
|
|
380
|
-
const [activeCell, setActiveCell] =
|
|
381
|
-
const [selectedRange, setSelectedRange] =
|
|
382
|
-
const [editingCell, setEditingCell] =
|
|
383
|
-
const [draftValue, setDraftValue] =
|
|
384
|
-
const controller =
|
|
609
|
+
const [activeCell, setActiveCell] = useState4(null);
|
|
610
|
+
const [selectedRange, setSelectedRange] = useState4(null);
|
|
611
|
+
const [editingCell, setEditingCell] = useState4(null);
|
|
612
|
+
const [draftValue, setDraftValue] = useState4("");
|
|
613
|
+
const controller = useMemo4(() => {
|
|
385
614
|
return new SpreadsheetController({
|
|
386
615
|
...options,
|
|
387
616
|
onDocumentChange: (updated) => {
|
|
@@ -398,82 +627,82 @@ function useSpreadsheetEditor(options = {}) {
|
|
|
398
627
|
}
|
|
399
628
|
});
|
|
400
629
|
}, []);
|
|
401
|
-
const setCellValue =
|
|
630
|
+
const setCellValue = useCallback4((rowId, colId, raw) => {
|
|
402
631
|
controller.setCellValue(rowId, colId, raw);
|
|
403
632
|
setDoc({ ...controller.document });
|
|
404
633
|
}, [controller]);
|
|
405
|
-
const selectCell =
|
|
634
|
+
const selectCell = useCallback4((row, col, extendSelection = false) => {
|
|
406
635
|
controller.selectCell(row, col, extendSelection);
|
|
407
636
|
setActiveCell(controller.activeCell);
|
|
408
637
|
setSelectedRange(controller.selectedRange);
|
|
409
638
|
}, [controller]);
|
|
410
|
-
const selectRange =
|
|
639
|
+
const selectRange = useCallback4((range) => {
|
|
411
640
|
controller.selectRange(range);
|
|
412
641
|
setSelectedRange(controller.selectedRange);
|
|
413
642
|
}, [controller]);
|
|
414
|
-
const startEditing =
|
|
643
|
+
const startEditing = useCallback4((row, col, initialVal) => {
|
|
415
644
|
controller.startEditing(row, col, initialVal);
|
|
416
645
|
setActiveCell(controller.activeCell);
|
|
417
646
|
setEditingCell(controller.editingCell);
|
|
418
647
|
setDraftValue(controller.draftValue);
|
|
419
648
|
}, [controller]);
|
|
420
|
-
const commitEditing =
|
|
649
|
+
const commitEditing = useCallback4((val) => {
|
|
421
650
|
controller.commitEditing(val);
|
|
422
651
|
setEditingCell(null);
|
|
423
652
|
setDraftValue("");
|
|
424
653
|
setDoc({ ...controller.document });
|
|
425
654
|
}, [controller]);
|
|
426
|
-
const cancelEditing =
|
|
655
|
+
const cancelEditing = useCallback4(() => {
|
|
427
656
|
controller.cancelEditing();
|
|
428
657
|
setEditingCell(null);
|
|
429
658
|
setDraftValue("");
|
|
430
659
|
}, [controller]);
|
|
431
|
-
const moveCursor =
|
|
660
|
+
const moveCursor = useCallback4((dir, extend = false) => {
|
|
432
661
|
controller.moveCursor(dir, extend);
|
|
433
662
|
setActiveCell(controller.activeCell);
|
|
434
663
|
setSelectedRange(controller.selectedRange);
|
|
435
664
|
}, [controller]);
|
|
436
|
-
const insertColumn =
|
|
665
|
+
const insertColumn = useCallback4((index, config) => {
|
|
437
666
|
controller.insertColumn(index, config);
|
|
438
667
|
setDoc({ ...controller.document });
|
|
439
668
|
}, [controller]);
|
|
440
|
-
const deleteColumn =
|
|
669
|
+
const deleteColumn = useCallback4((colId) => {
|
|
441
670
|
controller.deleteColumn(colId);
|
|
442
671
|
setDoc({ ...controller.document });
|
|
443
672
|
}, [controller]);
|
|
444
|
-
const insertRow =
|
|
673
|
+
const insertRow = useCallback4((index, config) => {
|
|
445
674
|
controller.insertRow(index, config);
|
|
446
675
|
setDoc({ ...controller.document });
|
|
447
676
|
}, [controller]);
|
|
448
|
-
const deleteRow =
|
|
677
|
+
const deleteRow = useCallback4((rowId) => {
|
|
449
678
|
controller.deleteRow(rowId);
|
|
450
679
|
setDoc({ ...controller.document });
|
|
451
680
|
}, [controller]);
|
|
452
|
-
const setColumnWidth =
|
|
681
|
+
const setColumnWidth = useCallback4((colId, width) => {
|
|
453
682
|
controller.setColumnWidth(colId, width);
|
|
454
683
|
setDoc({ ...controller.document });
|
|
455
684
|
}, [controller]);
|
|
456
|
-
const autoFitColumnWidth =
|
|
685
|
+
const autoFitColumnWidth = useCallback4((colId, customWidth) => {
|
|
457
686
|
controller.autoFitColumnWidth(colId, customWidth);
|
|
458
687
|
setDoc({ ...controller.document });
|
|
459
688
|
}, [controller]);
|
|
460
|
-
const registerDataSource =
|
|
689
|
+
const registerDataSource = useCallback4((ds) => {
|
|
461
690
|
controller.registerDataSource(ds);
|
|
462
691
|
setDoc({ ...controller.document });
|
|
463
692
|
}, [controller]);
|
|
464
|
-
const setPrimaryDataSource =
|
|
693
|
+
const setPrimaryDataSource = useCallback4((id) => {
|
|
465
694
|
controller.setPrimaryDataSource(id);
|
|
466
695
|
setDoc({ ...controller.document });
|
|
467
696
|
}, [controller]);
|
|
468
|
-
const recalculateAll =
|
|
697
|
+
const recalculateAll = useCallback4(() => {
|
|
469
698
|
controller.recalculateAll();
|
|
470
699
|
setDoc({ ...controller.document });
|
|
471
700
|
}, [controller]);
|
|
472
|
-
const undo =
|
|
701
|
+
const undo = useCallback4(() => {
|
|
473
702
|
controller.undo();
|
|
474
703
|
setDoc({ ...controller.document });
|
|
475
704
|
}, [controller]);
|
|
476
|
-
const redo =
|
|
705
|
+
const redo = useCallback4(() => {
|
|
477
706
|
controller.redo();
|
|
478
707
|
setDoc({ ...controller.document });
|
|
479
708
|
}, [controller]);
|
|
@@ -526,7 +755,7 @@ function useSpreadsheetEditor(options = {}) {
|
|
|
526
755
|
}
|
|
527
756
|
|
|
528
757
|
// src/spreadsheet/SpreadsheetEditor.tsx
|
|
529
|
-
import { useRef as
|
|
758
|
+
import { useRef as useRef5, useState as useState5, useMemo as useMemo5, useEffect as useEffect5, useCallback as useCallback5 } from "react";
|
|
530
759
|
import {
|
|
531
760
|
indexToColName
|
|
532
761
|
} from "@pixerate/editor";
|
|
@@ -541,36 +770,36 @@ var SpreadsheetEditor = ({
|
|
|
541
770
|
}) => {
|
|
542
771
|
const defaultState = useSpreadsheetEditor();
|
|
543
772
|
const state = externalState || defaultState;
|
|
544
|
-
const gridRef =
|
|
545
|
-
const [resizingColId, setResizingColId] =
|
|
546
|
-
const [hoveredColId, setHoveredColId] =
|
|
547
|
-
const [resizeStartX, setResizeStartX] =
|
|
548
|
-
const [resizeStartWidth, setResizeStartWidth] =
|
|
549
|
-
const activeRawValue =
|
|
773
|
+
const gridRef = useRef5(null);
|
|
774
|
+
const [resizingColId, setResizingColId] = useState5(null);
|
|
775
|
+
const [hoveredColId, setHoveredColId] = useState5(null);
|
|
776
|
+
const [resizeStartX, setResizeStartX] = useState5(0);
|
|
777
|
+
const [resizeStartWidth, setResizeStartWidth] = useState5(0);
|
|
778
|
+
const activeRawValue = useMemo5(() => {
|
|
550
779
|
if (!state.activeCell) return "";
|
|
551
780
|
const row = state.document.rows[state.activeCell.row];
|
|
552
781
|
const col = state.document.columns[state.activeCell.col];
|
|
553
782
|
if (!row || !col) return "";
|
|
554
783
|
return state.getCell(row.id, col.id).raw;
|
|
555
784
|
}, [state.activeCell, state.document]);
|
|
556
|
-
const coordLabel =
|
|
785
|
+
const coordLabel = useMemo5(() => {
|
|
557
786
|
if (!state.activeCell) return "--";
|
|
558
787
|
const colName = indexToColName(state.activeCell.col);
|
|
559
788
|
return `${colName}${state.activeCell.row + 1}`;
|
|
560
789
|
}, [state.activeCell]);
|
|
561
|
-
const handleCellClick =
|
|
790
|
+
const handleCellClick = useCallback5((rIdx, cIdx, e) => {
|
|
562
791
|
if (state.editingCell && (state.editingCell.row !== rIdx || state.editingCell.col !== cIdx)) {
|
|
563
792
|
state.commitEditing();
|
|
564
793
|
}
|
|
565
794
|
state.selectCell(rIdx, cIdx, e.shiftKey);
|
|
566
795
|
}, [state]);
|
|
567
|
-
const handleCellDblClick =
|
|
796
|
+
const handleCellDblClick = useCallback5((rIdx, cIdx) => {
|
|
568
797
|
if (readOnly) return;
|
|
569
798
|
const col = state.document.columns[cIdx];
|
|
570
799
|
if (col?.readOnly) return;
|
|
571
800
|
state.startEditing(rIdx, cIdx);
|
|
572
801
|
}, [readOnly, state]);
|
|
573
|
-
const handleKeyDown =
|
|
802
|
+
const handleKeyDown = useCallback5((e) => {
|
|
574
803
|
if (state.editingCell) {
|
|
575
804
|
if (e.key === "Enter") {
|
|
576
805
|
e.preventDefault();
|
|
@@ -634,7 +863,7 @@ var SpreadsheetEditor = ({
|
|
|
634
863
|
}
|
|
635
864
|
}
|
|
636
865
|
}, [readOnly, state]);
|
|
637
|
-
|
|
866
|
+
useEffect5(() => {
|
|
638
867
|
if (!resizingColId) return;
|
|
639
868
|
if (typeof document !== "undefined") {
|
|
640
869
|
document.body.style.cursor = "col-resize";
|
|
@@ -688,7 +917,7 @@ var SpreadsheetEditor = ({
|
|
|
688
917
|
window.removeEventListener("mouseup", handleMouseUp);
|
|
689
918
|
};
|
|
690
919
|
}, [resizingColId, resizeStartX, resizeStartWidth, state, onColumnResize]);
|
|
691
|
-
const measureElementContentWidth =
|
|
920
|
+
const measureElementContentWidth = useCallback5((el, container) => {
|
|
692
921
|
if (typeof document === "undefined") return 0;
|
|
693
922
|
let maxW = el.scrollWidth || 0;
|
|
694
923
|
const firstChild = el.firstElementChild;
|
|
@@ -736,7 +965,7 @@ var SpreadsheetEditor = ({
|
|
|
736
965
|
}
|
|
737
966
|
return maxW;
|
|
738
967
|
}, []);
|
|
739
|
-
const autoFitColumn =
|
|
968
|
+
const autoFitColumn = useCallback5((colId, colIndex) => {
|
|
740
969
|
const col = state.document.columns.find((c) => c.id === colId);
|
|
741
970
|
if (!col) return;
|
|
742
971
|
let calculatedWidth = 0;
|
|
@@ -773,12 +1002,12 @@ var SpreadsheetEditor = ({
|
|
|
773
1002
|
onColumnResize(updatedCol.id, updatedCol.width || 130);
|
|
774
1003
|
}
|
|
775
1004
|
}, [state, measureElementContentWidth, onColumnResize]);
|
|
776
|
-
const handleResizeDblClick =
|
|
1005
|
+
const handleResizeDblClick = useCallback5((colId, colIndex, e) => {
|
|
777
1006
|
e.preventDefault();
|
|
778
1007
|
e.stopPropagation();
|
|
779
1008
|
autoFitColumn(colId, colIndex);
|
|
780
1009
|
}, [autoFitColumn]);
|
|
781
|
-
const handleHeaderDblClick =
|
|
1010
|
+
const handleHeaderDblClick = useCallback5((colId, colIndex, e) => {
|
|
782
1011
|
const target = e.currentTarget;
|
|
783
1012
|
if (target) {
|
|
784
1013
|
const rect = target.getBoundingClientRect();
|
|
@@ -963,10 +1192,19 @@ var SpreadsheetEditor = ({
|
|
|
963
1192
|
};
|
|
964
1193
|
export {
|
|
965
1194
|
BubbleMenu,
|
|
1195
|
+
DirtyTracker,
|
|
966
1196
|
EditorContent,
|
|
1197
|
+
HistoryManager2 as HistoryManager,
|
|
967
1198
|
SpreadsheetEditor,
|
|
968
1199
|
TemplateRenderer,
|
|
1200
|
+
createDirtyTracker,
|
|
1201
|
+
createHistoryManager2 as createHistoryManager,
|
|
1202
|
+
defaultIsEqual,
|
|
1203
|
+
useDismissGuard,
|
|
969
1204
|
useEditor2 as useEditor,
|
|
1205
|
+
useHistory,
|
|
1206
|
+
useHistoryShortcuts,
|
|
1207
|
+
useNavigationGuard,
|
|
970
1208
|
usePromptEditor,
|
|
971
1209
|
useSpreadsheetEditor
|
|
972
1210
|
};
|