noteloom 0.3.0 → 0.3.2
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 +14 -30
- package/dist/index.d.ts +42 -6
- package/dist/noteloom.cjs +290 -8
- package/dist/noteloom.cjs.map +1 -1
- package/dist/noteloom.es.js +6041 -5447
- package/dist/noteloom.es.js.map +1 -1
- package/dist/style.css +282 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -440,41 +440,25 @@ A comment thread is `{ id, blockId, anchorRunIds, resolved, messages: [{ id, aut
|
|
|
440
440
|
|
|
441
441
|
## Version history
|
|
442
442
|
|
|
443
|
-
Point-in-time document snapshots
|
|
443
|
+
Google Docs-style — there's no "type a label and save" step. Point-in-time document snapshots (stored in IndexedDB, a third object store alongside `usePersistedDocument`'s `documents` and Templates' `templates`) are captured automatically after each burst of edits settles down, each one attributed to whoever made the changes. `examples/07-version-history/` is a complete runnable app.
|
|
444
444
|
|
|
445
445
|
```jsx
|
|
446
|
-
import {
|
|
447
|
-
|
|
448
|
-
// Automatic: snapshot every few minutes, keep the most recent 50.
|
|
449
|
-
useEffect(() => {
|
|
450
|
-
const snapshotter = createPeriodicVersionSnapshotter({ store: editor.store, docId, intervalMs: 5 * 60 * 1000 });
|
|
451
|
-
return () => snapshotter.stop();
|
|
452
|
-
}, [editor.store, docId]);
|
|
453
|
-
|
|
454
|
-
// Manual: "save a version now" button.
|
|
455
|
-
async function saveNow(label) {
|
|
456
|
-
const doc = JSON.parse(exportDocumentJSON(editor.store)); // exportDocumentJSON returns a JSON *string* — parse it first
|
|
457
|
-
await saveDocumentVersion({ id: crypto.randomUUID(), docId, timestamp: Date.now(), label, doc });
|
|
458
|
-
}
|
|
446
|
+
import { useEditor, NoteloomEditor, VersionHistory } from 'noteloom';
|
|
459
447
|
|
|
460
|
-
//
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
<ul>
|
|
466
|
-
{versions.map((v) => (
|
|
467
|
-
<li key={v.id}>
|
|
468
|
-
{v.label ?? '(untitled)'} — {new Date(v.timestamp).toLocaleString()}
|
|
469
|
-
<button onClick={() => applyDocumentTemplate(editor.store, v.doc)}>Restore</button>
|
|
470
|
-
</li>
|
|
471
|
-
))}
|
|
472
|
-
</ul>
|
|
473
|
-
);
|
|
474
|
-
}
|
|
448
|
+
const editor = useEditor({ currentUserId: currentUser.id }); // stamps every edit's author, see below
|
|
449
|
+
|
|
450
|
+
<NoteloomEditor editor={editor}>
|
|
451
|
+
<VersionHistory docId={docId} />
|
|
452
|
+
</NoteloomEditor>;
|
|
475
453
|
```
|
|
476
454
|
|
|
477
|
-
|
|
455
|
+
That's the whole integration. `<VersionHistory>` is self-contained: it renders the "Version history" button, and for as long as it's mounted it also quietly captures snapshots in the background — no separate wiring needed. Clicking the button opens a drawer (matching the built-in Comments UI's own design language) listing every version grouped by day, each showing an avatar, author, relative time, and a lightweight summary ("3 blocks changed"); clicking one opens it on a **Changes** tab — a word-level diff against the version right before it, insertions highlighted green, deletions struck through in red, Google Docs "show changes"-style — with a **Preview** tab alongside for a plain read-only render, and a "Restore this version" button.
|
|
456
|
+
|
|
457
|
+
**Attribution** — `currentUserId` (passed to `useEditor()`, or `history.setDefaultActorId(id)`/`new History(store, { defaultActorId })` for the granular API) is stamped as every edit's `actorId` automatically; `VersionHistory`/`createAutoVersionHistory` read it straight off the history log, no separate identity plumbing required. Omit it and versions still get created, just with `authorId: null` (shown as "Unknown").
|
|
458
|
+
|
|
459
|
+
**Tuning the capture window** — `<VersionHistory docId idleMs={5 * 60 * 1000} maxVersions={200} />`: `idleMs` (default 5 minutes) is how long edits need to pause before a version is closed and saved (a smaller value in the example app, so you don't have to actually wait); `maxVersions` prunes the oldest versions beyond that count. For the granular API, or to save an explicit snapshot right before some risky action, use `createAutoVersionHistory({ store, docId, idleMs?, maxVersions? })` directly — it returns `{ stop, flush }`; `flush()` closes and saves the current window immediately instead of waiting for the idle gap (e.g. right before navigating away).
|
|
460
|
+
|
|
461
|
+
Restoring needs no new function — it's the exact same `applyDocumentTemplate(store, doc)` Templates already uses to wholesale-replace a live editor's content, which is what the drawer's own Restore button calls. `saveDocumentVersion`/`loadDocumentVersion`/`deleteDocumentVersion`/`listDocumentVersions` are the raw storage operations everything above is built on, for anywhere the built-in UI doesn't fit; `useDocumentVersions(docId)` is the reactive hook if you want to build your own list instead of `<VersionHistory>`; `diffDocumentsHTML(prevDoc, nextDoc)` is the diffing function behind the Changes tab (pass `null` as `prevDoc` to mark everything as newly added), for building a custom diff view instead.
|
|
478
462
|
|
|
479
463
|
## Right-to-left / multi-language text
|
|
480
464
|
|
package/dist/index.d.ts
CHANGED
|
@@ -148,6 +148,8 @@ export interface HistoryOptions {
|
|
|
148
148
|
idleMs?: number;
|
|
149
149
|
trackChanges?: boolean;
|
|
150
150
|
maxChangeLogSize?: number;
|
|
151
|
+
/** Stamped as every edit's actorId when a perform/performBatch call doesn't pass its own -- see useEditor's `currentUserId`. */
|
|
152
|
+
defaultActorId?: string | null;
|
|
151
153
|
}
|
|
152
154
|
|
|
153
155
|
export interface HistoryLogEntry {
|
|
@@ -171,6 +173,8 @@ export interface OperationMeta {
|
|
|
171
173
|
export class History {
|
|
172
174
|
constructor(store: EditorStore, options?: HistoryOptions);
|
|
173
175
|
store: EditorStore;
|
|
176
|
+
defaultActorId: string | null;
|
|
177
|
+
setDefaultActorId(actorId: string | null): void;
|
|
174
178
|
|
|
175
179
|
getBlock(id: string): Block | undefined;
|
|
176
180
|
getRun(id: string): Run | undefined;
|
|
@@ -384,6 +388,13 @@ export interface DocumentVersion {
|
|
|
384
388
|
id: string;
|
|
385
389
|
docId: string;
|
|
386
390
|
timestamp: number;
|
|
391
|
+
/** Whoever made the most recent edit in this version's window -- read from History's defaultActorId, null if never configured. */
|
|
392
|
+
authorId?: string | null;
|
|
393
|
+
/** Every distinct actorId that contributed to this version's window. */
|
|
394
|
+
authorIds?: string[];
|
|
395
|
+
/** Lightweight auto-generated description (e.g. "3 blocks changed") -- not a full diff. */
|
|
396
|
+
summary?: string;
|
|
397
|
+
/** Only ever set by renaming a version yourself -- nothing in this package's automatic capture sets it. */
|
|
387
398
|
label?: string;
|
|
388
399
|
doc: DocumentJSON;
|
|
389
400
|
}
|
|
@@ -394,16 +405,21 @@ export function deleteDocumentVersion(id: string): Promise<void>;
|
|
|
394
405
|
/** All versions saved for docId, newest first. */
|
|
395
406
|
export function listDocumentVersions(docId: string): Promise<DocumentVersion[]>;
|
|
396
407
|
|
|
397
|
-
/**
|
|
398
|
-
|
|
399
|
-
|
|
408
|
+
/**
|
|
409
|
+
* Automatic, Google Docs-style version history -- no "name it and save"
|
|
410
|
+
* step. `store` must be a History instance (needs getHistoryLog()/
|
|
411
|
+
* subscribeToHistory()). Saves one snapshot after each burst of edits
|
|
412
|
+
* settles (idleMs of inactivity), attributed to whoever made them.
|
|
413
|
+
*/
|
|
414
|
+
export function createAutoVersionHistory(options: {
|
|
415
|
+
store: History;
|
|
400
416
|
docId: string;
|
|
401
|
-
|
|
402
|
-
|
|
417
|
+
/** Inactivity gap that closes a version's window. Default 5 minutes. */
|
|
418
|
+
idleMs?: number;
|
|
403
419
|
maxVersions?: number;
|
|
404
420
|
onSnapshot?: (version: DocumentVersion) => void;
|
|
405
421
|
onError?: (error: unknown) => void;
|
|
406
|
-
}): { stop: () => void };
|
|
422
|
+
}): { stop: () => void; flush: () => Promise<void> };
|
|
407
423
|
|
|
408
424
|
export function useDocumentVersions(docId: string | null | undefined): {
|
|
409
425
|
versions: DocumentVersion[];
|
|
@@ -411,6 +427,24 @@ export function useDocumentVersions(docId: string | null | undefined): {
|
|
|
411
427
|
refresh: () => Promise<void>;
|
|
412
428
|
};
|
|
413
429
|
|
|
430
|
+
/**
|
|
431
|
+
* Google Docs "show changes"-style HTML diff of `nextDoc` against `prevDoc`
|
|
432
|
+
* (pass null/undefined for prevDoc to mark everything as newly added) --
|
|
433
|
+
* word-level insertions/deletions wrapped in `.be-version-diff-added`/
|
|
434
|
+
* `.be-version-diff-removed` spans. Used internally by `<VersionHistory>`'s
|
|
435
|
+
* "Changes" tab; exported for building a custom version-history UI.
|
|
436
|
+
*/
|
|
437
|
+
export function diffDocumentsHTML(prevDoc: DocumentJSON | null | undefined, nextDoc: DocumentJSON): string;
|
|
438
|
+
|
|
439
|
+
export interface VersionHistoryProps {
|
|
440
|
+
docId: string;
|
|
441
|
+
idleMs?: number;
|
|
442
|
+
maxVersions?: number;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/** Self-contained "Version history" button + drawer (list/preview/restore) -- also owns the automatic capture (createAutoVersionHistory) for as long as it's mounted. `store` (from context) must be a History instance. */
|
|
446
|
+
export const VersionHistory: ComponentType<VersionHistoryProps>;
|
|
447
|
+
|
|
414
448
|
// ---------------------------------------------------------------------------
|
|
415
449
|
// comments/
|
|
416
450
|
// ---------------------------------------------------------------------------
|
|
@@ -815,6 +849,8 @@ export interface UseEditorOptions {
|
|
|
815
849
|
doc?: DocumentJSON;
|
|
816
850
|
/** true (default): store is undo/redo-aware (a History instance). false: a plain EditorStore. */
|
|
817
851
|
history?: boolean;
|
|
852
|
+
/** Stamped as every edit's actorId (History's defaultActorId) -- used by createAutoVersionHistory/VersionHistory for "who changed this", with no separate identity plumbing needed. Ignored when history: false. */
|
|
853
|
+
currentUserId?: string | null;
|
|
818
854
|
/** Replaces registerBuiltInBlocks for an opt-in subset of block types. */
|
|
819
855
|
registerBlocks?: (registry: BlockRegistry) => void;
|
|
820
856
|
/** Replaces registerBuiltInInlineTypes for an opt-in subset of inline types. */
|