@pixerate/editor-react 0.14.0 → 0.16.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 +6 -1
- package/dist/canvas/index.cjs +352 -118
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +112 -8
- package/dist/canvas/index.d.ts +112 -8
- package/dist/canvas/index.js +258 -19
- package/dist/canvas/index.js.map +1 -1
- package/dist/chunk-4ZC2WCUO.js +196 -0
- package/dist/chunk-4ZC2WCUO.js.map +1 -0
- package/dist/chunk-7SPRQZ6H.js +216 -0
- package/dist/chunk-7SPRQZ6H.js.map +1 -0
- package/dist/{chunk-25S5EHH4.js → chunk-FYIPXHAE.js} +22 -13
- package/dist/chunk-FYIPXHAE.js.map +1 -0
- package/dist/{chunk-TL27COKM.js → chunk-XTFR3IMK.js} +683 -286
- package/dist/chunk-XTFR3IMK.js.map +1 -0
- package/dist/chunk-XWFU2CSG.js +167 -0
- package/dist/chunk-XWFU2CSG.js.map +1 -0
- package/dist/commands/index.cjs +232 -0
- package/dist/commands/index.cjs.map +1 -0
- package/dist/commands/index.d.cts +69 -0
- package/dist/commands/index.d.ts +69 -0
- package/dist/commands/index.js +13 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/generation/index.cjs +235 -0
- package/dist/generation/index.cjs.map +1 -0
- package/dist/generation/index.d.cts +60 -0
- package/dist/generation/index.d.ts +60 -0
- package/dist/generation/index.js +13 -0
- package/dist/generation/index.js.map +1 -0
- package/dist/image-editor/index.cjs +688 -299
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +65 -5
- package/dist/image-editor/index.d.ts +65 -5
- package/dist/image-editor/index.js +13 -3
- package/dist/index.cjs +2200 -683
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +201 -23
- package/dist/index.d.ts +201 -23
- package/dist/index.js +743 -129
- package/dist/index.js.map +1 -1
- package/dist/persistence/index.cjs +191 -0
- package/dist/persistence/index.cjs.map +1 -0
- package/dist/persistence/index.d.cts +77 -0
- package/dist/persistence/index.d.ts +77 -0
- package/dist/persistence/index.js +9 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/spreadsheet/index.cjs +17 -10
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +9 -7
- package/dist/spreadsheet/index.d.ts +9 -7
- package/dist/spreadsheet/index.js +1 -1
- package/package.json +26 -2
- package/dist/chunk-25S5EHH4.js.map +0 -1
- package/dist/chunk-TL27COKM.js.map +0 -1
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/persistence/index.ts
|
|
21
|
+
var persistence_exports = {};
|
|
22
|
+
__export(persistence_exports, {
|
|
23
|
+
RecoveryPrompt: () => RecoveryPrompt,
|
|
24
|
+
useAutosave: () => useAutosave
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(persistence_exports);
|
|
27
|
+
|
|
28
|
+
// src/persistence/useAutosave.ts
|
|
29
|
+
var import_react = require("react");
|
|
30
|
+
var import_persistence = require("@pixerate/editor/persistence");
|
|
31
|
+
var IDLE = {
|
|
32
|
+
status: "idle",
|
|
33
|
+
error: null,
|
|
34
|
+
failures: 0,
|
|
35
|
+
nextAttemptAt: null,
|
|
36
|
+
lastSavedAt: null,
|
|
37
|
+
ready: false
|
|
38
|
+
};
|
|
39
|
+
function useAutosave(options) {
|
|
40
|
+
const optionsRef = (0, import_react.useRef)(options);
|
|
41
|
+
optionsRef.current = options;
|
|
42
|
+
const { storage, key, history, dirty } = options;
|
|
43
|
+
const recover = options.recover !== false;
|
|
44
|
+
const flushOnHide = options.flushOnHide !== false;
|
|
45
|
+
const ready = options.ready !== false;
|
|
46
|
+
const [controller, setController] = (0, import_react.useState)(null);
|
|
47
|
+
const [status, setStatus] = (0, import_react.useState)(IDLE);
|
|
48
|
+
const [recovery, setRecovery] = (0, import_react.useState)(null);
|
|
49
|
+
const [pendingRecovery, setPendingRecovery] = (0, import_react.useState)(recover);
|
|
50
|
+
const revisionsRef = (0, import_react.useRef)(null);
|
|
51
|
+
(0, import_react.useEffect)(() => {
|
|
52
|
+
const revisions = (0, import_persistence.createRevisionTracker)({ history, dirty });
|
|
53
|
+
const o = optionsRef.current;
|
|
54
|
+
const instance = (0, import_persistence.createAutosaveController)({
|
|
55
|
+
storage,
|
|
56
|
+
key,
|
|
57
|
+
getSnapshot: () => optionsRef.current.getSnapshot(),
|
|
58
|
+
serialize: o.serialize,
|
|
59
|
+
deserialize: o.deserialize,
|
|
60
|
+
name: () => optionsRef.current.name,
|
|
61
|
+
revision: revisions.revision,
|
|
62
|
+
savedRevision: revisions.savedRevision,
|
|
63
|
+
interval: o.interval,
|
|
64
|
+
debounceMs: o.debounceMs,
|
|
65
|
+
retryBaseMs: o.retryBaseMs,
|
|
66
|
+
retryMaxMs: o.retryMaxMs
|
|
67
|
+
});
|
|
68
|
+
const unsubscribeStatus = instance.subscribe(setStatus);
|
|
69
|
+
const unsubscribeRevisions = revisions.subscribe(() => instance.notify());
|
|
70
|
+
revisionsRef.current = revisions;
|
|
71
|
+
setController(instance);
|
|
72
|
+
setStatus(instance.getStatus());
|
|
73
|
+
let active = true;
|
|
74
|
+
if (recover) {
|
|
75
|
+
setPendingRecovery(true);
|
|
76
|
+
instance.checkRecovery().catch(() => null).then((found) => {
|
|
77
|
+
if (!active) return;
|
|
78
|
+
setRecovery(found);
|
|
79
|
+
setPendingRecovery(found !== null);
|
|
80
|
+
});
|
|
81
|
+
} else {
|
|
82
|
+
setRecovery(null);
|
|
83
|
+
setPendingRecovery(false);
|
|
84
|
+
}
|
|
85
|
+
return () => {
|
|
86
|
+
active = false;
|
|
87
|
+
unsubscribeStatus();
|
|
88
|
+
unsubscribeRevisions();
|
|
89
|
+
revisions.destroy();
|
|
90
|
+
instance.destroy();
|
|
91
|
+
if (revisionsRef.current === revisions) revisionsRef.current = null;
|
|
92
|
+
};
|
|
93
|
+
}, [storage, key, history, dirty, recover]);
|
|
94
|
+
(0, import_react.useEffect)(() => {
|
|
95
|
+
if (controller && ready && !pendingRecovery) controller.ready();
|
|
96
|
+
}, [controller, ready, pendingRecovery]);
|
|
97
|
+
(0, import_react.useEffect)(() => {
|
|
98
|
+
if (!controller || !flushOnHide || typeof window === "undefined") return;
|
|
99
|
+
const flush = () => void controller.flushNow();
|
|
100
|
+
const onVisibility = () => {
|
|
101
|
+
if (document.visibilityState === "hidden") flush();
|
|
102
|
+
};
|
|
103
|
+
window.addEventListener("pagehide", flush);
|
|
104
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
105
|
+
return () => {
|
|
106
|
+
window.removeEventListener("pagehide", flush);
|
|
107
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
108
|
+
};
|
|
109
|
+
}, [controller, flushOnHide]);
|
|
110
|
+
const restore = (0, import_react.useCallback)(() => {
|
|
111
|
+
const snapshot = recovery?.snapshot;
|
|
112
|
+
setRecovery(null);
|
|
113
|
+
setPendingRecovery(false);
|
|
114
|
+
return snapshot;
|
|
115
|
+
}, [recovery]);
|
|
116
|
+
const discard = (0, import_react.useCallback)(async () => {
|
|
117
|
+
if (controller) await controller.discardRecovery();
|
|
118
|
+
setRecovery(null);
|
|
119
|
+
setPendingRecovery(false);
|
|
120
|
+
}, [controller]);
|
|
121
|
+
const flushNow = (0, import_react.useCallback)(async () => {
|
|
122
|
+
await controller?.flushNow();
|
|
123
|
+
}, [controller]);
|
|
124
|
+
const markClean = (0, import_react.useCallback)(async () => {
|
|
125
|
+
revisionsRef.current?.markSaved();
|
|
126
|
+
await controller?.markClean();
|
|
127
|
+
}, [controller]);
|
|
128
|
+
const notifyChange = (0, import_react.useCallback)(() => revisionsRef.current?.bump(), []);
|
|
129
|
+
return { status, recovery, pendingRecovery, restore, discard, flushNow, markClean, notifyChange, controller };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// src/persistence/RecoveryPrompt.tsx
|
|
133
|
+
var import_persistence2 = require("@pixerate/editor/persistence");
|
|
134
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
135
|
+
var RecoveryPrompt = ({
|
|
136
|
+
recovery,
|
|
137
|
+
onRestore,
|
|
138
|
+
onDiscard,
|
|
139
|
+
formatTime,
|
|
140
|
+
restoreLabel = "Restore",
|
|
141
|
+
discardLabel = "Discard",
|
|
142
|
+
className = ""
|
|
143
|
+
}) => {
|
|
144
|
+
if (!recovery) return null;
|
|
145
|
+
const { name } = recovery.meta;
|
|
146
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
147
|
+
"div",
|
|
148
|
+
{
|
|
149
|
+
role: "alertdialog",
|
|
150
|
+
"aria-label": "Unsaved changes found",
|
|
151
|
+
"data-recovery-prompt": "",
|
|
152
|
+
className: `flex flex-wrap items-center gap-3 rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground shadow-sm ${className}`,
|
|
153
|
+
children: [
|
|
154
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "min-w-0 flex-1", children: [
|
|
155
|
+
(0, import_persistence2.formatRecoveryMessage)(recovery.meta, formatTime),
|
|
156
|
+
name ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "ml-1 text-xs text-muted-foreground", children: [
|
|
157
|
+
"(",
|
|
158
|
+
name,
|
|
159
|
+
")"
|
|
160
|
+
] }) : null
|
|
161
|
+
] }),
|
|
162
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
163
|
+
"button",
|
|
164
|
+
{
|
|
165
|
+
type: "button",
|
|
166
|
+
"data-recovery-restore": "",
|
|
167
|
+
onClick: onRestore,
|
|
168
|
+
className: "rounded-md bg-primary px-3 py-1 text-xs font-medium text-primary-foreground hover:opacity-90",
|
|
169
|
+
children: restoreLabel
|
|
170
|
+
}
|
|
171
|
+
),
|
|
172
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
173
|
+
"button",
|
|
174
|
+
{
|
|
175
|
+
type: "button",
|
|
176
|
+
"data-recovery-discard": "",
|
|
177
|
+
onClick: onDiscard,
|
|
178
|
+
className: "rounded-md border border-border px-3 py-1 text-xs font-medium hover:bg-muted",
|
|
179
|
+
children: discardLabel
|
|
180
|
+
}
|
|
181
|
+
)
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
};
|
|
186
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
187
|
+
0 && (module.exports = {
|
|
188
|
+
RecoveryPrompt,
|
|
189
|
+
useAutosave
|
|
190
|
+
});
|
|
191
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/persistence/index.ts","../../src/persistence/useAutosave.ts","../../src/persistence/RecoveryPrompt.tsx"],"sourcesContent":["export * from './useAutosave';\nexport * from './RecoveryPrompt';\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n createAutosaveController,\n createRevisionTracker,\n type AutosaveController,\n type AutosaveRecovery,\n type AutosaveStatusInfo,\n type DirtyFlagSource,\n type RevisionChangeSource,\n type RevisionTracker,\n type StorageAdapter,\n} from '@pixerate/editor/persistence';\n\nexport interface UseAutosaveOptions<T> {\n storage: StorageAdapter;\n /** Snapshot key (the meta lives at `<key>:meta`). */\n key: string;\n /** Reads the current document (the latest function is always used). */\n getSnapshot: () => T;\n serialize?: (snapshot: T) => string;\n deserialize?: (text: string) => T;\n /** Document name stored with the snapshot. */\n name?: string;\n /** Change notifications, e.g. a `HistoryManager`. */\n history?: RevisionChangeSource;\n /** Saved-vs-current flag, e.g. `useHistoryDirty().tracker` or a `bindDirtyToHistory` binding. */\n dirty?: DirtyFlagSource;\n interval?: number;\n debounceMs?: number;\n retryBaseMs?: number;\n retryMaxMs?: number;\n /**\n * Whether the document has finished loading (default `true`). Snapshots start\n * once this is true and any recovered snapshot was restored or discarded.\n */\n ready?: boolean;\n /** Look for an earlier session's snapshot on mount (default `true`). */\n recover?: boolean;\n /** Write pending changes on `pagehide` and when the tab is hidden (default `true`). */\n flushOnHide?: boolean;\n}\n\nexport interface UseAutosaveResult<T> {\n status: AutosaveStatusInfo;\n /** An earlier session's unsaved snapshot, until restored or discarded. */\n recovery: AutosaveRecovery<T> | null;\n /** True while the recovery check runs or a recovered snapshot awaits a decision. */\n pendingRecovery: boolean;\n /** Takes the recovered snapshot (apply it to the editor) and starts autosaving. */\n restore: () => T | undefined;\n /** Deletes the recovered snapshot and starts autosaving. */\n discard: () => Promise<void>;\n /** Writes pending changes now. */\n flushNow: () => Promise<void>;\n /** Call after an explicit save: marks the current revision saved and retires this session's snapshot. */\n markClean: () => Promise<void>;\n /** Records a change made outside `history`. */\n notifyChange: () => void;\n controller: AutosaveController<T> | null;\n}\n\nconst IDLE: AutosaveStatusInfo = {\n status: 'idle',\n error: null,\n failures: 0,\n nextAttemptAt: null,\n lastSavedAt: null,\n ready: false,\n};\n\n/**\n * Crash-recovery autosave bound to a history and dirty flag, with page\n * lifecycle flushing and a recovery check on mount (see\n * `createAutosaveController` in `@pixerate/editor/persistence`). Render\n * `<RecoveryPrompt>` with `recovery`, `restore` and `discard`.\n */\nexport function useAutosave<T>(options: UseAutosaveOptions<T>): UseAutosaveResult<T> {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n const { storage, key, history, dirty } = options;\n const recover = options.recover !== false;\n const flushOnHide = options.flushOnHide !== false;\n const ready = options.ready !== false;\n\n const [controller, setController] = useState<AutosaveController<T> | null>(null);\n const [status, setStatus] = useState<AutosaveStatusInfo>(IDLE);\n const [recovery, setRecovery] = useState<AutosaveRecovery<T> | null>(null);\n const [pendingRecovery, setPendingRecovery] = useState(recover);\n const revisionsRef = useRef<RevisionTracker | null>(null);\n\n useEffect(() => {\n const revisions = createRevisionTracker({ history, dirty });\n const o = optionsRef.current;\n const instance = createAutosaveController<T>({\n storage,\n key,\n getSnapshot: () => optionsRef.current.getSnapshot(),\n serialize: o.serialize,\n deserialize: o.deserialize,\n name: () => optionsRef.current.name,\n revision: revisions.revision,\n savedRevision: revisions.savedRevision,\n interval: o.interval,\n debounceMs: o.debounceMs,\n retryBaseMs: o.retryBaseMs,\n retryMaxMs: o.retryMaxMs,\n });\n const unsubscribeStatus = instance.subscribe(setStatus);\n const unsubscribeRevisions = revisions.subscribe(() => instance.notify());\n revisionsRef.current = revisions;\n setController(instance);\n setStatus(instance.getStatus());\n\n let active = true;\n if (recover) {\n setPendingRecovery(true);\n instance\n .checkRecovery()\n .catch(() => null)\n .then((found) => {\n if (!active) return;\n setRecovery(found);\n setPendingRecovery(found !== null);\n });\n } else {\n setRecovery(null);\n setPendingRecovery(false);\n }\n\n return () => {\n active = false;\n unsubscribeStatus();\n unsubscribeRevisions();\n revisions.destroy();\n instance.destroy();\n if (revisionsRef.current === revisions) revisionsRef.current = null;\n };\n }, [storage, key, history, dirty, recover]);\n\n useEffect(() => {\n if (controller && ready && !pendingRecovery) controller.ready();\n }, [controller, ready, pendingRecovery]);\n\n useEffect(() => {\n if (!controller || !flushOnHide || typeof window === 'undefined') return;\n const flush = () => void controller.flushNow();\n const onVisibility = () => {\n if (document.visibilityState === 'hidden') flush();\n };\n window.addEventListener('pagehide', flush);\n document.addEventListener('visibilitychange', onVisibility);\n return () => {\n window.removeEventListener('pagehide', flush);\n document.removeEventListener('visibilitychange', onVisibility);\n };\n }, [controller, flushOnHide]);\n\n const restore = useCallback(() => {\n const snapshot = recovery?.snapshot;\n setRecovery(null);\n setPendingRecovery(false);\n return snapshot;\n }, [recovery]);\n\n const discard = useCallback(async () => {\n if (controller) await controller.discardRecovery();\n setRecovery(null);\n setPendingRecovery(false);\n }, [controller]);\n\n const flushNow = useCallback(async () => {\n await controller?.flushNow();\n }, [controller]);\n\n const markClean = useCallback(async () => {\n revisionsRef.current?.markSaved();\n await controller?.markClean();\n }, [controller]);\n\n const notifyChange = useCallback(() => revisionsRef.current?.bump(), []);\n\n return { status, recovery, pendingRecovery, restore, discard, flushNow, markClean, notifyChange, controller };\n}\n","import React from 'react';\nimport { formatRecoveryMessage, type RecoveryMeta } from '@pixerate/editor/persistence';\n\nexport interface RecoveryPromptProps {\n /** `useAutosave().recovery`; nothing renders while it is `null`. */\n recovery: { meta: RecoveryMeta } | null;\n onRestore: () => void;\n onDiscard: () => void;\n /** Formats the snapshot time (default `toLocaleString`). */\n formatTime?: (time: number) => string;\n restoreLabel?: string;\n discardLabel?: string;\n className?: string;\n}\n\n/**\n * \"Restore unsaved changes from <time>?\" banner with Restore / Discard buttons\n * (Tailwind + theme tokens).\n */\nexport const RecoveryPrompt: React.FC<RecoveryPromptProps> = ({\n recovery,\n onRestore,\n onDiscard,\n formatTime,\n restoreLabel = 'Restore',\n discardLabel = 'Discard',\n className = '',\n}) => {\n if (!recovery) return null;\n const { name } = recovery.meta;\n return (\n <div\n role=\"alertdialog\"\n aria-label=\"Unsaved changes found\"\n data-recovery-prompt=\"\"\n className={`flex flex-wrap items-center gap-3 rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground shadow-sm ${className}`}\n >\n <span className=\"min-w-0 flex-1\">\n {formatRecoveryMessage(recovery.meta, formatTime)}\n {name ? <span className=\"ml-1 text-xs text-muted-foreground\">({name})</span> : null}\n </span>\n <button\n type=\"button\"\n data-recovery-restore=\"\"\n onClick={onRestore}\n className=\"rounded-md bg-primary px-3 py-1 text-xs font-medium text-primary-foreground hover:opacity-90\"\n >\n {restoreLabel}\n </button>\n <button\n type=\"button\"\n data-recovery-discard=\"\"\n onClick={onDiscard}\n className=\"rounded-md border border-border px-3 py-1 text-xs font-medium hover:bg-muted\"\n >\n {discardLabel}\n </button>\n </div>\n );\n};\n"],"mappings":"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","names":["import_persistence"]}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { StorageAdapter, RevisionChangeSource, DirtyFlagSource, AutosaveStatusInfo, AutosaveRecovery, AutosaveController, RecoveryMeta } from '@pixerate/editor/persistence';
|
|
2
|
+
import React__default from 'react';
|
|
3
|
+
|
|
4
|
+
interface UseAutosaveOptions<T> {
|
|
5
|
+
storage: StorageAdapter;
|
|
6
|
+
/** Snapshot key (the meta lives at `<key>:meta`). */
|
|
7
|
+
key: string;
|
|
8
|
+
/** Reads the current document (the latest function is always used). */
|
|
9
|
+
getSnapshot: () => T;
|
|
10
|
+
serialize?: (snapshot: T) => string;
|
|
11
|
+
deserialize?: (text: string) => T;
|
|
12
|
+
/** Document name stored with the snapshot. */
|
|
13
|
+
name?: string;
|
|
14
|
+
/** Change notifications, e.g. a `HistoryManager`. */
|
|
15
|
+
history?: RevisionChangeSource;
|
|
16
|
+
/** Saved-vs-current flag, e.g. `useHistoryDirty().tracker` or a `bindDirtyToHistory` binding. */
|
|
17
|
+
dirty?: DirtyFlagSource;
|
|
18
|
+
interval?: number;
|
|
19
|
+
debounceMs?: number;
|
|
20
|
+
retryBaseMs?: number;
|
|
21
|
+
retryMaxMs?: number;
|
|
22
|
+
/**
|
|
23
|
+
* Whether the document has finished loading (default `true`). Snapshots start
|
|
24
|
+
* once this is true and any recovered snapshot was restored or discarded.
|
|
25
|
+
*/
|
|
26
|
+
ready?: boolean;
|
|
27
|
+
/** Look for an earlier session's snapshot on mount (default `true`). */
|
|
28
|
+
recover?: boolean;
|
|
29
|
+
/** Write pending changes on `pagehide` and when the tab is hidden (default `true`). */
|
|
30
|
+
flushOnHide?: boolean;
|
|
31
|
+
}
|
|
32
|
+
interface UseAutosaveResult<T> {
|
|
33
|
+
status: AutosaveStatusInfo;
|
|
34
|
+
/** An earlier session's unsaved snapshot, until restored or discarded. */
|
|
35
|
+
recovery: AutosaveRecovery<T> | null;
|
|
36
|
+
/** True while the recovery check runs or a recovered snapshot awaits a decision. */
|
|
37
|
+
pendingRecovery: boolean;
|
|
38
|
+
/** Takes the recovered snapshot (apply it to the editor) and starts autosaving. */
|
|
39
|
+
restore: () => T | undefined;
|
|
40
|
+
/** Deletes the recovered snapshot and starts autosaving. */
|
|
41
|
+
discard: () => Promise<void>;
|
|
42
|
+
/** Writes pending changes now. */
|
|
43
|
+
flushNow: () => Promise<void>;
|
|
44
|
+
/** Call after an explicit save: marks the current revision saved and retires this session's snapshot. */
|
|
45
|
+
markClean: () => Promise<void>;
|
|
46
|
+
/** Records a change made outside `history`. */
|
|
47
|
+
notifyChange: () => void;
|
|
48
|
+
controller: AutosaveController<T> | null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Crash-recovery autosave bound to a history and dirty flag, with page
|
|
52
|
+
* lifecycle flushing and a recovery check on mount (see
|
|
53
|
+
* `createAutosaveController` in `@pixerate/editor/persistence`). Render
|
|
54
|
+
* `<RecoveryPrompt>` with `recovery`, `restore` and `discard`.
|
|
55
|
+
*/
|
|
56
|
+
declare function useAutosave<T>(options: UseAutosaveOptions<T>): UseAutosaveResult<T>;
|
|
57
|
+
|
|
58
|
+
interface RecoveryPromptProps {
|
|
59
|
+
/** `useAutosave().recovery`; nothing renders while it is `null`. */
|
|
60
|
+
recovery: {
|
|
61
|
+
meta: RecoveryMeta;
|
|
62
|
+
} | null;
|
|
63
|
+
onRestore: () => void;
|
|
64
|
+
onDiscard: () => void;
|
|
65
|
+
/** Formats the snapshot time (default `toLocaleString`). */
|
|
66
|
+
formatTime?: (time: number) => string;
|
|
67
|
+
restoreLabel?: string;
|
|
68
|
+
discardLabel?: string;
|
|
69
|
+
className?: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* "Restore unsaved changes from <time>?" banner with Restore / Discard buttons
|
|
73
|
+
* (Tailwind + theme tokens).
|
|
74
|
+
*/
|
|
75
|
+
declare const RecoveryPrompt: React__default.FC<RecoveryPromptProps>;
|
|
76
|
+
|
|
77
|
+
export { RecoveryPrompt, type RecoveryPromptProps, type UseAutosaveOptions, type UseAutosaveResult, useAutosave };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { StorageAdapter, RevisionChangeSource, DirtyFlagSource, AutosaveStatusInfo, AutosaveRecovery, AutosaveController, RecoveryMeta } from '@pixerate/editor/persistence';
|
|
2
|
+
import React__default from 'react';
|
|
3
|
+
|
|
4
|
+
interface UseAutosaveOptions<T> {
|
|
5
|
+
storage: StorageAdapter;
|
|
6
|
+
/** Snapshot key (the meta lives at `<key>:meta`). */
|
|
7
|
+
key: string;
|
|
8
|
+
/** Reads the current document (the latest function is always used). */
|
|
9
|
+
getSnapshot: () => T;
|
|
10
|
+
serialize?: (snapshot: T) => string;
|
|
11
|
+
deserialize?: (text: string) => T;
|
|
12
|
+
/** Document name stored with the snapshot. */
|
|
13
|
+
name?: string;
|
|
14
|
+
/** Change notifications, e.g. a `HistoryManager`. */
|
|
15
|
+
history?: RevisionChangeSource;
|
|
16
|
+
/** Saved-vs-current flag, e.g. `useHistoryDirty().tracker` or a `bindDirtyToHistory` binding. */
|
|
17
|
+
dirty?: DirtyFlagSource;
|
|
18
|
+
interval?: number;
|
|
19
|
+
debounceMs?: number;
|
|
20
|
+
retryBaseMs?: number;
|
|
21
|
+
retryMaxMs?: number;
|
|
22
|
+
/**
|
|
23
|
+
* Whether the document has finished loading (default `true`). Snapshots start
|
|
24
|
+
* once this is true and any recovered snapshot was restored or discarded.
|
|
25
|
+
*/
|
|
26
|
+
ready?: boolean;
|
|
27
|
+
/** Look for an earlier session's snapshot on mount (default `true`). */
|
|
28
|
+
recover?: boolean;
|
|
29
|
+
/** Write pending changes on `pagehide` and when the tab is hidden (default `true`). */
|
|
30
|
+
flushOnHide?: boolean;
|
|
31
|
+
}
|
|
32
|
+
interface UseAutosaveResult<T> {
|
|
33
|
+
status: AutosaveStatusInfo;
|
|
34
|
+
/** An earlier session's unsaved snapshot, until restored or discarded. */
|
|
35
|
+
recovery: AutosaveRecovery<T> | null;
|
|
36
|
+
/** True while the recovery check runs or a recovered snapshot awaits a decision. */
|
|
37
|
+
pendingRecovery: boolean;
|
|
38
|
+
/** Takes the recovered snapshot (apply it to the editor) and starts autosaving. */
|
|
39
|
+
restore: () => T | undefined;
|
|
40
|
+
/** Deletes the recovered snapshot and starts autosaving. */
|
|
41
|
+
discard: () => Promise<void>;
|
|
42
|
+
/** Writes pending changes now. */
|
|
43
|
+
flushNow: () => Promise<void>;
|
|
44
|
+
/** Call after an explicit save: marks the current revision saved and retires this session's snapshot. */
|
|
45
|
+
markClean: () => Promise<void>;
|
|
46
|
+
/** Records a change made outside `history`. */
|
|
47
|
+
notifyChange: () => void;
|
|
48
|
+
controller: AutosaveController<T> | null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Crash-recovery autosave bound to a history and dirty flag, with page
|
|
52
|
+
* lifecycle flushing and a recovery check on mount (see
|
|
53
|
+
* `createAutosaveController` in `@pixerate/editor/persistence`). Render
|
|
54
|
+
* `<RecoveryPrompt>` with `recovery`, `restore` and `discard`.
|
|
55
|
+
*/
|
|
56
|
+
declare function useAutosave<T>(options: UseAutosaveOptions<T>): UseAutosaveResult<T>;
|
|
57
|
+
|
|
58
|
+
interface RecoveryPromptProps {
|
|
59
|
+
/** `useAutosave().recovery`; nothing renders while it is `null`. */
|
|
60
|
+
recovery: {
|
|
61
|
+
meta: RecoveryMeta;
|
|
62
|
+
} | null;
|
|
63
|
+
onRestore: () => void;
|
|
64
|
+
onDiscard: () => void;
|
|
65
|
+
/** Formats the snapshot time (default `toLocaleString`). */
|
|
66
|
+
formatTime?: (time: number) => string;
|
|
67
|
+
restoreLabel?: string;
|
|
68
|
+
discardLabel?: string;
|
|
69
|
+
className?: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* "Restore unsaved changes from <time>?" banner with Restore / Discard buttons
|
|
73
|
+
* (Tailwind + theme tokens).
|
|
74
|
+
*/
|
|
75
|
+
declare const RecoveryPrompt: React__default.FC<RecoveryPromptProps>;
|
|
76
|
+
|
|
77
|
+
export { RecoveryPrompt, type RecoveryPromptProps, type UseAutosaveOptions, type UseAutosaveResult, useAutosave };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -269,11 +269,12 @@ var SpreadsheetContextMenu = ({ items, x, y, onClose }) => {
|
|
|
269
269
|
type: "button",
|
|
270
270
|
role: "menuitem",
|
|
271
271
|
"data-action": item.id,
|
|
272
|
+
"data-checked": item.checked ? "" : void 0,
|
|
272
273
|
disabled: item.disabled,
|
|
273
|
-
className:
|
|
274
|
+
className: `block w-full px-3 py-1 text-left hover:bg-muted disabled:cursor-default disabled:opacity-40 disabled:hover:bg-transparent ${item.checked ? "font-semibold" : ""}`,
|
|
274
275
|
onClick: () => {
|
|
275
276
|
onClose();
|
|
276
|
-
|
|
277
|
+
(0, import_spreadsheet2.runSpreadsheetMenuItem)(item);
|
|
277
278
|
},
|
|
278
279
|
children: item.label
|
|
279
280
|
}
|
|
@@ -583,6 +584,19 @@ function spillBorderStyle(range, row, col) {
|
|
|
583
584
|
borderRight: col === range.endCol ? line : void 0
|
|
584
585
|
};
|
|
585
586
|
}
|
|
587
|
+
function CellText({ cell }) {
|
|
588
|
+
const shown = (0, import_spreadsheet5.formatCellForDisplay)(cell);
|
|
589
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
590
|
+
"span",
|
|
591
|
+
{
|
|
592
|
+
className: `truncate block max-w-full ${cell.error ? "text-destructive font-semibold" : ""}`,
|
|
593
|
+
title: cell.error ? cell.errorMessage ?? cell.error : void 0,
|
|
594
|
+
"data-numeric": shown.numeric ? "" : void 0,
|
|
595
|
+
style: shown.numeric || shown.color ? { ...shown.numeric ? { textAlign: "right" } : {}, ...shown.color ? { color: (0, import_spreadsheet5.numberFormatColorToCss)(shown.color) } : {} } : void 0,
|
|
596
|
+
children: shown.text
|
|
597
|
+
}
|
|
598
|
+
);
|
|
599
|
+
}
|
|
586
600
|
var SpreadsheetEditor = ({
|
|
587
601
|
state: externalState,
|
|
588
602
|
readOnly = false,
|
|
@@ -1114,14 +1128,7 @@ var SpreadsheetEditor = ({
|
|
|
1114
1128
|
}
|
|
1115
1129
|
),
|
|
1116
1130
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(FormulaHints, { inputRef: cellInputRef, value: state.draftValue, onAccept: state.setDraftValue })
|
|
1117
|
-
] }) : customCellRenderer ? customCellRenderer({ row, col, cell }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1118
|
-
"span",
|
|
1119
|
-
{
|
|
1120
|
-
className: `truncate block max-w-full ${cell.error ? "text-destructive font-semibold" : ""}`,
|
|
1121
|
-
title: cell.error ? cell.errorMessage ?? cell.error : void 0,
|
|
1122
|
-
children: cell.error || (cell.value ?? "")
|
|
1123
|
-
}
|
|
1124
|
-
),
|
|
1131
|
+
] }) : customCellRenderer ? customCellRenderer({ row, col, cell }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CellText, { cell }),
|
|
1125
1132
|
activeSpill && (0, import_spreadsheet5.rangeContains)(activeSpill.range, rIdx, cIdx) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "aria-hidden": "true", className: "spreadsheet-spill-border", style: spillBorderStyle(activeSpill.range, rIdx, cIdx) }),
|
|
1126
1133
|
showFillHandle && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1127
1134
|
"div",
|