@fileverse-dev/dsheet 4.1.23-stabilise-package-1 → 4.1.23-stabilise-package-3
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 +10 -0
- package/dist/editor/contexts/editor-context.d.ts +2 -0
- package/dist/editor/hooks/use-editor-data.d.ts +1 -0
- package/dist/editor/types.d.ts +14 -3
- package/dist/editor/utils/after-update-cell.d.ts +4 -0
- package/dist/editor/utils/format-gate.d.ts +8 -4
- package/dist/editor/utils/legacy-on-change.d.ts +20 -0
- package/dist/editor/utils/legacy-on-change.test.d.ts +1 -0
- package/dist/editor/utils/rebuild-indexeddb-store.d.ts +8 -1
- package/dist/editor/utils/remote-apply-guard.d.ts +25 -3
- package/dist/editor/utils/wait-for-sync.d.ts +35 -0
- package/dist/editor/utils/wait-for-sync.test.d.ts +1 -0
- package/dist/{executeStringFunction-DKA5MuP0.js → executeStringFunction-D5BTPrXL.js} +9414 -9324
- package/dist/formula.js +1 -1
- package/dist/{index-ypRdpDnX.js → index-BXNWi7s5.js} +12266 -12081
- package/dist/index.es.js +29 -29
- package/dist/sheet-engine/core/api/sheet-flowdata-lifecycle.d.ts +1 -0
- package/dist/sheet-engine/core/api/sheet-flowdata-lifecycle.test.d.ts +1 -0
- package/dist/sheet-engine/core/modules/formula.d.ts +9 -0
- package/dist/sheet-engine/core/modules/history-calc-chain.d.ts +6 -0
- package/dist/sheet-engine/core/modules/history-grid-size.d.ts +16 -0
- package/dist/sheet-engine/core/modules/history-grid-size.test.d.ts +1 -0
- package/dist/sheet-engine/core/settings.d.ts +9 -1
- package/dist/sheet-engine/core/utils/ydoc-celldata-changes.d.ts +14 -3
- package/dist/{use-xlsx-import-impl-DQ3tpIAe.js → use-xlsx-import-impl-gsG9w9qV.js} +4 -4
- package/dist/{xlsx-defined-names-CVVLxbe-.js → xlsx-defined-names-dZveijsB.js} +2 -2
- package/dist/{xlsx-export-impl-ghSoFZBz.js → xlsx-export-impl-B10lK_L2.js} +4 -4
- package/dist/{xlsx-hyperlink-inline-DXj7AkSf.js → xlsx-hyperlink-inline-BFbPe75M.js} +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -86,6 +86,7 @@ function App() {
|
|
|
86
86
|
| `isCollaborative` | `boolean` | `false` | Enable collaborative features |
|
|
87
87
|
| `enableWebrtc` | `boolean` | `true` | Enable WebRTC for P2P collaboration |
|
|
88
88
|
| `enableIndexeddbSync` | `boolean` | `true` | Enable local IndexedDB persistence |
|
|
89
|
+
| `onIndexedDbError` | `(error: Error) => void` | - | Called when local persistence fails, or when the first read of the local store does not finish within 15 s. The editor continues with the in-memory document; call `rebuildLocalStore()` to recreate the store |
|
|
89
90
|
| `isTemplateOpen` | `boolean` | - | Template sidebar state |
|
|
90
91
|
| `selectedTemplate` | `string` | - | Selected template identifier |
|
|
91
92
|
| `onboardingComplete` | `boolean` | - | Onboarding completion status |
|
|
@@ -115,6 +116,15 @@ function App() {
|
|
|
115
116
|
| `setInputFetchURLDataBlock` | `Dispatch<SetStateAction<string>>` | URL input state setter |
|
|
116
117
|
| `setForceSheetRender` | `Dispatch<SetStateAction<number>>` | Force re-render trigger |
|
|
117
118
|
|
|
119
|
+
### Editor handle methods
|
|
120
|
+
|
|
121
|
+
`sheetEditorRef` is a `DSheetEditorHandle`: the workbook instance plus these methods.
|
|
122
|
+
|
|
123
|
+
| Method | Description |
|
|
124
|
+
|--------|-------------|
|
|
125
|
+
| `rebuildLocalStore()` | `Promise<void>`. Deletes this sheet's IndexedDB database and rewrites it from the live document, so local edits are kept. A no-op when read-only or when `enableIndexeddbSync` is off. Rejects if the rebuild fails, the new store does not sync within 15 s, or a refresh or unmount supersedes it. Concurrent calls share one rebuild. |
|
|
126
|
+
| `getContentFingerprint()` | `string \| null`. Changes on every document change, deletes included; compare with `===` only. `null` until local persistence has synced. |
|
|
127
|
+
|
|
118
128
|
## Examples
|
|
119
129
|
|
|
120
130
|
### Read-Only Viewer
|
|
@@ -43,6 +43,8 @@ export interface EditorContextType {
|
|
|
43
43
|
setSheetData: React.Dispatch<React.SetStateAction<Sheet[]>>;
|
|
44
44
|
currentDataRef: React.MutableRefObject<Sheet[]>;
|
|
45
45
|
remoteUpdateRef: React.MutableRefObject<boolean>;
|
|
46
|
+
/** True while a peer's structural edit waits to remount the grid. */
|
|
47
|
+
structuralRemountPendingRef: React.MutableRefObject<boolean>;
|
|
46
48
|
handleChange: (data: Sheet[]) => void;
|
|
47
49
|
initialiseLiveQueryData: (data: Sheet[]) => void;
|
|
48
50
|
loading: boolean;
|
|
@@ -21,6 +21,7 @@ export declare const useEditorData: (ydocRef: React.MutableRefObject<Y.Doc | nul
|
|
|
21
21
|
setSheetData: import('react').Dispatch<import('react').SetStateAction<Sheet[]>>;
|
|
22
22
|
currentDataRef: import('react').MutableRefObject<Sheet[]>;
|
|
23
23
|
remoteUpdateRef: import('react').MutableRefObject<boolean>;
|
|
24
|
+
structuralRemountPendingRef: import('react').MutableRefObject<boolean>;
|
|
24
25
|
isDataLoaded: boolean;
|
|
25
26
|
setIsDataLoaded: import('react').Dispatch<import('react').SetStateAction<boolean>>;
|
|
26
27
|
handleChange: (_data: Sheet[]) => void;
|
package/dist/editor/types.d.ts
CHANGED
|
@@ -33,7 +33,13 @@ export type DSheetEditorHandle = WorkbookInstance & {
|
|
|
33
33
|
* document (same Y.Doc, never replaced), so local edits are kept. Resolves
|
|
34
34
|
* once the new store has synced. Resolves as a no-op when the editor is
|
|
35
35
|
* read-only, local persistence is disabled or there is no sheet id. Rejects
|
|
36
|
-
* if the rebuild fails
|
|
36
|
+
* if the rebuild fails, if the new store does not sync within 15 s, or if a
|
|
37
|
+
* refresh/unmount supersedes it. Concurrent calls share one rebuild.
|
|
38
|
+
*
|
|
39
|
+
* A bootstrap that is still waiting on an unreadable store (the case this
|
|
40
|
+
* heals) is abandoned after 3 s: the rebuild then finishes the bootstrap
|
|
41
|
+
* itself, merging the published content into the document, so the editor
|
|
42
|
+
* leaves "syncing" once the rebuild resolves.
|
|
37
43
|
*/
|
|
38
44
|
rebuildLocalStore: () => Promise<void>;
|
|
39
45
|
terminateSession: () => void;
|
|
@@ -111,12 +117,17 @@ export interface DsheetProps {
|
|
|
111
117
|
/**
|
|
112
118
|
* @deprecated Encodes the whole Y.Doc and rebuilds a plain workbook per
|
|
113
119
|
* call. Use `onContentChange` and read full state on demand. Called at most
|
|
114
|
-
* once per second (trailing), flushed only on unload and unmount.
|
|
120
|
+
* once per second (trailing), flushed only on unload and unmount. The latest
|
|
121
|
+
* `onChange` you pass is the one called, so an inline function is safe: a new
|
|
122
|
+
* identity does not cancel a pending call.
|
|
115
123
|
*/
|
|
116
124
|
onChange?: (updateData: SheetUpdateData, encodedUpdate?: string) => void;
|
|
117
125
|
collaboration?: CollaborationProps;
|
|
118
126
|
/** Called when local IndexedDB persistence fails. The editor and durable
|
|
119
|
-
* collaboration continue using the in-memory Y.Doc, matching dDoc.
|
|
127
|
+
* collaboration continue using the in-memory Y.Doc, matching dDoc. Also
|
|
128
|
+
* called when the first read of the local store does not finish within 15 s
|
|
129
|
+
* (the editor then continues without local persistence, and
|
|
130
|
+
* `rebuildLocalStore()` can recreate the store). */
|
|
120
131
|
onIndexedDbError?: (error: Error) => void;
|
|
121
132
|
username?: string;
|
|
122
133
|
portalContent?: string;
|
|
@@ -50,9 +50,13 @@ interface AfterUpdateCellParams {
|
|
|
50
50
|
collabEnabled?: boolean;
|
|
51
51
|
collabIsOwner?: boolean;
|
|
52
52
|
remoteUpdateRef?: React.MutableRefObject<boolean>;
|
|
53
|
+
/** True while a peer's structural edit waits to remount the grid. */
|
|
54
|
+
structuralRemountPendingRef?: React.MutableRefObject<boolean>;
|
|
53
55
|
localUserEditRef?: React.MutableRefObject<boolean>;
|
|
54
56
|
/** Sheet that held the cell at commit time; falls back to the current sheet. */
|
|
55
57
|
sheetId?: string;
|
|
58
|
+
/** The caller writes the cell to Yjs itself (paste and fill batch writes). */
|
|
59
|
+
skipPersist?: boolean;
|
|
56
60
|
}
|
|
57
61
|
/** True when data-block formulas (API / smart contract) should run for this edit. */
|
|
58
62
|
export declare const shouldExecuteDataBlocks: (params: {
|
|
@@ -15,9 +15,13 @@ export declare function readFormatVersion(doc: Y.Doc, dsheetId: string): number;
|
|
|
15
15
|
*/
|
|
16
16
|
export declare function isFormatLocked(doc: Y.Doc | null | undefined, dsheetId?: string): boolean;
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* Make the grid read-only in the same tick the lock is seen. The Yjs writers
|
|
19
|
+
* stop at once (isFormatLocked), but the grid became read-only only after the
|
|
20
|
+
* workbook data changed identity and the Workbook init effect ran: a commit in
|
|
21
|
+
* between showed in the grid, never reached Yjs, and was gone on reload.
|
|
22
|
+
* The Workbook init effect sets the same flag from the prop afterwards.
|
|
22
23
|
*/
|
|
24
|
+
export declare function lockWorkbookReadOnly(workbook: {
|
|
25
|
+
getWorkbookSetContext?: () => unknown;
|
|
26
|
+
} | null | undefined): boolean;
|
|
23
27
|
export declare function watchFormatGate(doc: Y.Doc, dsheetId: string, onLocked: (format: number) => void): () => void;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** The legacy `onChange` argument pair: plain sheet data and the encoded doc. */
|
|
2
|
+
export type LegacyOnChangeArgs = {
|
|
3
|
+
data: unknown;
|
|
4
|
+
update: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const LEGACY_ON_CHANGE_WAIT_MS = 1000;
|
|
7
|
+
/**
|
|
8
|
+
* Trailing-only throttle for the host's legacy `onChange`.
|
|
9
|
+
*
|
|
10
|
+
* The host's handler is read when the throttle fires, not when it is created.
|
|
11
|
+
* A host that passes a new inline `onChange` on every render must not rebuild
|
|
12
|
+
* this throttle: rebuilding cancels the pending call, so an edit followed
|
|
13
|
+
* within the wait by a re-render never reached the host's save.
|
|
14
|
+
* `buildArgs` runs only when there is a handler, because it encodes the whole
|
|
15
|
+
* document.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createLegacyOnChangeThrottle<TData>(getOnChange: () => ((data: TData, update: string) => void) | undefined, buildArgs: () => {
|
|
18
|
+
data: TData;
|
|
19
|
+
update: string;
|
|
20
|
+
} | null, waitMs?: number): any;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -8,5 +8,12 @@ import type * as Y from 'yjs';
|
|
|
8
8
|
* fresh row. `onCreated` runs right after the new provider is constructed,
|
|
9
9
|
* before it has synced, so the caller can track it and attach listeners. The Y.Doc is never replaced or cleared. Unlike delete-and-reopen
|
|
10
10
|
* (heal), edits that exist only in the live doc are kept.
|
|
11
|
+
*
|
|
12
|
+
* The wait for the new provider is bounded: `whenSynced` never rejects, and a
|
|
13
|
+
* provider destroyed before its first read (a bootstrap restarting meanwhile)
|
|
14
|
+
* never syncs. It rejects on `timeoutMs` or once `isCurrent()` is false.
|
|
11
15
|
*/
|
|
12
|
-
export declare function rebuildIndexedDbStore(dsheetId: string, doc: Y.Doc, current: IndexeddbPersistence | null, onCreated?: (provider: IndexeddbPersistence) => void
|
|
16
|
+
export declare function rebuildIndexedDbStore(dsheetId: string, doc: Y.Doc, current: IndexeddbPersistence | null, onCreated?: (provider: IndexeddbPersistence) => void, syncOptions?: {
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
isCurrent?: () => boolean;
|
|
19
|
+
}): Promise<IndexeddbPersistence>;
|
|
@@ -11,6 +11,18 @@ export type RemoteApplyGuardRefs = {
|
|
|
11
11
|
remoteApplyDepthRef: MutableRefObject<number>;
|
|
12
12
|
remoteUpdateRef: MutableRefObject<boolean>;
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* True when an engine → Yjs echo hook (calcChain, conditional formats, ...)
|
|
16
|
+
* must stay quiet: a remote apply is running, or a structural remount is
|
|
17
|
+
* pending. While one is pending the engine still has the grid from before the
|
|
18
|
+
* peer's insert or delete, so a diff of its metadata against Yjs would write
|
|
19
|
+
* the old coordinates over the peer's (and delete the peer's calcChain
|
|
20
|
+
* entries). Cell commits are not echo hooks and are not held back by this.
|
|
21
|
+
*/
|
|
22
|
+
export declare function shouldSkipEchoWrite(refs: {
|
|
23
|
+
remoteUpdateRef: MutableRefObject<boolean>;
|
|
24
|
+
structuralRemountPendingRef?: MutableRefObject<boolean>;
|
|
25
|
+
}): boolean;
|
|
14
26
|
export declare function syncRemoteUpdateFlag(refs: RemoteApplyGuardRefs): void;
|
|
15
27
|
export declare function beginRemoteApply(refs: RemoteApplyGuardRefs): void;
|
|
16
28
|
export declare function endRemoteApply(refs: RemoteApplyGuardRefs): void;
|
|
@@ -25,9 +37,12 @@ export type StructuralRemountRefs = RemoteApplyGuardRefs & {
|
|
|
25
37
|
* The guard is begun once, right before `run`, and ended after paint, so each
|
|
26
38
|
* remount owns exactly one begin and one end. It is NOT held while the timer
|
|
27
39
|
* is merely pending or deferred by a cell edit: `remoteUpdateRef` makes
|
|
28
|
-
* handleChange
|
|
29
|
-
* holding it across an edit would drop the user's
|
|
30
|
-
*
|
|
40
|
+
* handleChange and the data-block work in afterUpdateCell drop local work, so
|
|
41
|
+
* holding it across an edit would drop the user's typed edit. (The cell write
|
|
42
|
+
* in afterUpdateCell and the commit-time write do not check it.) What must not
|
|
43
|
+
* run while a remount is pending is the engine → Yjs echo hooks, which diff
|
|
44
|
+
* the old grid against Yjs: they check `shouldSkipEchoWrite`. Events that
|
|
45
|
+
* land while one is pending only re-arm its timer.
|
|
31
46
|
*
|
|
32
47
|
* While `isEditing()` is true at fire time the timer re-arms (250 ms) and the
|
|
33
48
|
* pending flag is kept; the remount runs once the edit ends.
|
|
@@ -41,5 +56,12 @@ export declare const STRUCTURAL_REMOUNT_EDIT_RETRY_MS = 250;
|
|
|
41
56
|
* to release here.
|
|
42
57
|
*/
|
|
43
58
|
export declare function cancelStructuralRemount(refs: StructuralRemountRefs): void;
|
|
59
|
+
/**
|
|
60
|
+
* Run `fn` under the guard and keep it until paint (a remount follows). If
|
|
61
|
+
* `fn` throws, the guard is ended at once and the error is rethrown: a begin
|
|
62
|
+
* with no matching end leaves the depth above zero, and `handleChange` then
|
|
63
|
+
* drops every local write until reload.
|
|
64
|
+
*/
|
|
65
|
+
export declare function runRemoteApplyUntilPaint<T>(refs: RemoteApplyGuardRefs, fn: () => T): T;
|
|
44
66
|
/** End after Workbook remount hooks have flushed (2 rAF ≈ one paint). */
|
|
45
67
|
export declare function endRemoteApplyAfterPaint(refs: RemoteApplyGuardRefs): void;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Waits for a y-indexeddb provider without trusting it to finish.
|
|
3
|
+
*
|
|
4
|
+
* In y-indexeddb 9.0.12 `whenSynced` resolves only on 'synced'. It has no
|
|
5
|
+
* reject path, and a provider that is destroyed before its first read, or whose
|
|
6
|
+
* first read never completes, never syncs. Awaiting it directly hangs the
|
|
7
|
+
* bootstrap, and a rebuild that waits for the bootstrap hangs with it.
|
|
8
|
+
*/
|
|
9
|
+
export declare const INDEXEDDB_SYNC_TIMEOUT_MS = 15000;
|
|
10
|
+
/** How long a rebuild waits for a running bootstrap before it abandons it. */
|
|
11
|
+
export declare const REBUILD_BOOTSTRAP_WAIT_MS = 3000;
|
|
12
|
+
export declare class PersistenceSyncTimeoutError extends Error {
|
|
13
|
+
constructor(ms: number);
|
|
14
|
+
}
|
|
15
|
+
export declare class PersistenceSupersededError extends Error {
|
|
16
|
+
constructor();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolves when `whenSynced` does. Rejects with PersistenceSyncTimeoutError
|
|
20
|
+
* after `timeoutMs`, or with PersistenceSupersededError as soon as
|
|
21
|
+
* `isCurrent()` turns false (checked every 100 ms): a newer bootstrap or an
|
|
22
|
+
* unmount owns the provider then, and it may already be destroyed.
|
|
23
|
+
*/
|
|
24
|
+
export declare function waitForPersistenceSynced(persistence: {
|
|
25
|
+
whenSynced: Promise<unknown>;
|
|
26
|
+
}, options?: {
|
|
27
|
+
timeoutMs?: number;
|
|
28
|
+
isCurrent?: () => boolean;
|
|
29
|
+
}): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Waits for a running bootstrap for at most `ms`. 'stuck' means it has not
|
|
32
|
+
* settled; the caller then abandons it (bumps the generation) instead of
|
|
33
|
+
* waiting for a provider that may never sync.
|
|
34
|
+
*/
|
|
35
|
+
export declare function waitForBootstrapOrAbandon(bootstrap: Promise<unknown>, ms?: number): Promise<'settled' | 'stuck'>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|