@templatical/core 0.48.0 → 0.49.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 +3 -1
- package/dist/cloud/index.d.ts +2 -53
- package/dist/cloud/index.js +2 -281
- package/dist/cloud/index.js.map +1 -1
- package/dist/index.d.ts +275 -7
- package/dist/index.js +1213 -15
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/dist/editor-Bl4WsPU3.d.ts +0 -105
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,115 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { ComputedRef, Ref } from "@vue/reactivity";
|
|
1
|
+
import { Block, BlockDefaults, BlockLock, BlockLockHolder, BlockType, CollaborationActor, CollaborationConflictCode, CollaborationConnectionState, CollaborationMember, CollaborationProvider, CollaborationRemoteChange, Comment, CommentAuthor, CommentInput, CommentPatch, CommentsListParams, CommentsProvider, CustomBlock, CustomBlockDefinition, MediaProvider, Operation, SavedBlock, SavedBlockPatch, SavedBlocksListParams, SavedBlocksProvider, Template, TemplateContent, TemplateDefaults, TemplateSaveTrigger, TemplateSettings, TemplateVersion, TemplatesProvider, UiTheme, VersionHistoryListParams, VersionHistoryProvider, ViewportSize } from "@templatical/types";
|
|
2
|
+
import { ComputedRef, DeepReadonly, Ref } from "@vue/reactivity";
|
|
4
3
|
import { ComputedRef as ComputedRef$1, Ref as Ref$1 } from "vue";
|
|
4
|
+
//#region src/editor.d.ts
|
|
5
|
+
interface EditorState {
|
|
6
|
+
/**
|
|
7
|
+
* The template currently being edited, as the store last returned it — `null`
|
|
8
|
+
* until `create()` or `load()` resolves, and always `null` without a
|
|
9
|
+
* {@link TemplatesProvider}.
|
|
10
|
+
*
|
|
11
|
+
* Carries identity and name only for practical purposes: its `content` is the
|
|
12
|
+
* store's copy from the last round-trip, whereas `state.content` is what the
|
|
13
|
+
* user is editing.
|
|
14
|
+
*/
|
|
15
|
+
template: Template | null;
|
|
16
|
+
content: TemplateContent;
|
|
17
|
+
selectedBlockId: string | null;
|
|
18
|
+
viewport: ViewportSize;
|
|
19
|
+
darkMode: boolean;
|
|
20
|
+
previewMode: boolean;
|
|
21
|
+
isDirty: boolean;
|
|
22
|
+
/** True for the duration of a `save()` call. */
|
|
23
|
+
isSaving: boolean;
|
|
24
|
+
/** True for the duration of a `create()` or `load()` call. */
|
|
25
|
+
isLoading: boolean;
|
|
26
|
+
uiTheme: UiTheme;
|
|
27
|
+
}
|
|
28
|
+
interface UseEditorOptions {
|
|
29
|
+
content: TemplateContent;
|
|
30
|
+
defaultFontFamily?: string;
|
|
31
|
+
templateDefaults?: TemplateDefaults;
|
|
32
|
+
/**
|
|
33
|
+
* Blocks other collaborators hold. A locked block can't be selected, and the
|
|
34
|
+
* editor's own mutators leave it alone.
|
|
35
|
+
*/
|
|
36
|
+
lockedBlocks?: Readonly<Ref<ReadonlyMap<string, unknown>>>;
|
|
37
|
+
/**
|
|
38
|
+
* Storage backend for the template's save/load lifecycle. Omit it and
|
|
39
|
+
* `create()` / `load()` / `save()` reject — the editor keeps working as a
|
|
40
|
+
* purely local editing surface.
|
|
41
|
+
*/
|
|
42
|
+
templates?: TemplatesProvider;
|
|
43
|
+
/**
|
|
44
|
+
* Called with any error a provider call rejects with, before the rejection is
|
|
45
|
+
* re-thrown to the caller.
|
|
46
|
+
*/
|
|
47
|
+
onError?: (error: Error) => void;
|
|
48
|
+
}
|
|
49
|
+
interface UseEditorReturn {
|
|
50
|
+
state: DeepReadonly<EditorState>;
|
|
51
|
+
content: Ref<TemplateContent>;
|
|
52
|
+
selectedBlock: Ref<Block | null>;
|
|
53
|
+
setContent: (content: TemplateContent, markDirty?: boolean) => void;
|
|
54
|
+
selectBlock: (blockId: string | null) => void;
|
|
55
|
+
setViewport: (viewport: ViewportSize) => void;
|
|
56
|
+
setDarkMode: (darkMode: boolean) => void;
|
|
57
|
+
setPreviewMode: (previewMode: boolean) => void;
|
|
58
|
+
setUiTheme: (theme: UiTheme) => void;
|
|
59
|
+
updateBlock: (blockId: string, updates: Partial<Block>) => void;
|
|
60
|
+
updateSettings: (updates: Partial<TemplateSettings>) => void;
|
|
61
|
+
addBlock: (block: Block, targetSectionId?: string, columnIndex?: number, index?: number) => void;
|
|
62
|
+
removeBlock: (blockId: string) => void;
|
|
63
|
+
moveBlock: (blockId: string, newIndex: number, targetSectionId?: string, columnIndex?: number) => void;
|
|
64
|
+
isBlockLocked: (blockId: string) => boolean;
|
|
65
|
+
markDirty: () => void;
|
|
66
|
+
findBlockLocation: (blockId: string) => {
|
|
67
|
+
targetSectionId?: string;
|
|
68
|
+
columnIndex?: number;
|
|
69
|
+
index: number;
|
|
70
|
+
} | null;
|
|
71
|
+
/**
|
|
72
|
+
* Rename the loaded template locally and mark the editor dirty. The new name
|
|
73
|
+
* reaches the store on the next `save()`, in the same patch as the content —
|
|
74
|
+
* a rename is an ordinary unsaved change, not a side channel.
|
|
75
|
+
*
|
|
76
|
+
* This method only stages it. The editor's inline rename field commits by
|
|
77
|
+
* calling `setName()` and then saving immediately, because a rename reads as a
|
|
78
|
+
* discrete action rather than an edit to be batched — so in the editor the
|
|
79
|
+
* "next `save()`" is usually the one it triggers itself. A headless caller
|
|
80
|
+
* decides its own moment.
|
|
81
|
+
*
|
|
82
|
+
* No-op when no template is loaded: there is nothing to name.
|
|
83
|
+
*/
|
|
84
|
+
setName: (name: string) => void;
|
|
85
|
+
/**
|
|
86
|
+
* Persist the current content as a new template. `input.content`, when given,
|
|
87
|
+
* replaces the editor's content first — so `create({ content })` both loads
|
|
88
|
+
* and stores in one step.
|
|
89
|
+
*/
|
|
90
|
+
create: (input?: {
|
|
91
|
+
name?: string;
|
|
92
|
+
content?: TemplateContent;
|
|
93
|
+
}) => Promise<Template>;
|
|
94
|
+
/** Fetch a template and make it the editor's content. */
|
|
95
|
+
load: (templateId: string) => Promise<Template>;
|
|
96
|
+
/**
|
|
97
|
+
* Persist the loaded template's name + content as a patch.
|
|
98
|
+
*
|
|
99
|
+
* `trigger` is passed through to `TemplatesOptions.onSaved`. It defaults to
|
|
100
|
+
* `"api"`, which is the honest answer for a direct call — the editor package
|
|
101
|
+
* passes the value matching whichever affordance fired.
|
|
102
|
+
*/
|
|
103
|
+
save: (trigger?: TemplateSaveTrigger) => Promise<Template>;
|
|
104
|
+
/** Whether a template has been created or loaded. */
|
|
105
|
+
hasTemplate: () => boolean;
|
|
106
|
+
}
|
|
107
|
+
export declare function useEditor(options: UseEditorOptions): UseEditorReturn;
|
|
108
|
+
//#endregion
|
|
5
109
|
//#region src/history.d.ts
|
|
6
110
|
interface UseHistoryOptions {
|
|
7
111
|
content: Ref<TemplateContent>;
|
|
8
112
|
setContent: (content: TemplateContent, markDirty?: boolean) => void;
|
|
9
|
-
isRemoteOperation?: () => boolean;
|
|
10
113
|
maxSize?: number;
|
|
11
114
|
}
|
|
12
115
|
interface UseHistoryReturn {
|
|
@@ -136,11 +239,176 @@ interface HistoryInterceptorEditor {
|
|
|
136
239
|
* Wraps editor mutation methods to record history snapshots before each
|
|
137
240
|
* operation. Mutates the editor object in place.
|
|
138
241
|
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
242
|
+
* Not installed with a collaboration provider: its controller captures
|
|
243
|
+
* changes by diffing the content and keeps its own undo history.
|
|
141
244
|
*/
|
|
142
245
|
export declare function useHistoryInterceptor(editor: HistoryInterceptorEditor, history: UseHistoryReturn): void;
|
|
143
246
|
//#endregion
|
|
247
|
+
//#region src/diff-content.d.ts
|
|
248
|
+
/**
|
|
249
|
+
* The operations that turn `before` into `after`. Blocks are matched by id, so
|
|
250
|
+
* a drag comes out as a `moveBlock` and a layout change as a `columns` change
|
|
251
|
+
* plus moves, never as deletions and re-additions.
|
|
252
|
+
*
|
|
253
|
+
* `applyOperations(before, diffContent(before, after))` deep-equals `after`
|
|
254
|
+
* when both are well formed: unique ids, sections only at the top level, and
|
|
255
|
+
* each section's `children` as long as its layout's column count. The order is
|
|
256
|
+
* what the engine needs:
|
|
257
|
+
*
|
|
258
|
+
* 1. Deletions that take nothing still needed with them.
|
|
259
|
+
* 2. The top level: additions (a new section carries its new children) and moves.
|
|
260
|
+
* 3. `columns` growth, so new columns exist before blocks move into them.
|
|
261
|
+
* 4. Every section column: additions and moves, out of shrinking columns too.
|
|
262
|
+
* 5. `columns` shrinkage, once the dropped columns are empty.
|
|
263
|
+
* 6. Deletion of sections whose surviving blocks have moved out.
|
|
264
|
+
* 7. Key changes on blocks, then on settings.
|
|
265
|
+
*
|
|
266
|
+
* No operation carries `expect`: an ordinary edit applies over anything that
|
|
267
|
+
* doesn't conflict with it, and locks keep two people off one block.
|
|
268
|
+
*/
|
|
269
|
+
export declare function diffContent(before: TemplateContent, after: TemplateContent): Operation[];
|
|
270
|
+
//#endregion
|
|
271
|
+
//#region src/invert-operations.d.ts
|
|
272
|
+
/**
|
|
273
|
+
* The batch that undoes `ops`, given the content they apply to. Each operation
|
|
274
|
+
* is inverted against the content just before it, and the inverses run in
|
|
275
|
+
* reverse order.
|
|
276
|
+
*
|
|
277
|
+
* Every inverse that can be guarded is: it expects what its operation left
|
|
278
|
+
* behind, so an undo that a later edit by someone else has overtaken is refused
|
|
279
|
+
* (`precondition_failed`, `anchor_missing`, `block_missing`) instead of
|
|
280
|
+
* overwriting that edit. A `setContent` inverse has no guard; the backend's
|
|
281
|
+
* `locked_by_others` rule is what stops it while others are editing.
|
|
282
|
+
*
|
|
283
|
+
* Throws the engine's `OperationError` when `ops` don't apply to `before`.
|
|
284
|
+
*/
|
|
285
|
+
export declare function invertOperations(before: TemplateContent, ops: readonly Operation[]): Operation[];
|
|
286
|
+
//#endregion
|
|
287
|
+
//#region src/collaboration.d.ts
|
|
288
|
+
/** The template fields the controller reads, as the editor's readonly state holds them. */
|
|
289
|
+
type CollaborationTemplate = DeepReadonly<Pick<Template, "id" | "revision" | "content">>;
|
|
290
|
+
/** The slice of the editor the controller reads and writes. */
|
|
291
|
+
interface CollaborationEditor {
|
|
292
|
+
state: {
|
|
293
|
+
readonly template: CollaborationTemplate | null;
|
|
294
|
+
readonly selectedBlockId: string | null;
|
|
295
|
+
readonly isLoading: boolean;
|
|
296
|
+
};
|
|
297
|
+
/** The live content the user edits. */
|
|
298
|
+
content: Ref<TemplateContent>;
|
|
299
|
+
selectBlock: (blockId: string | null) => void;
|
|
300
|
+
setContent: (content: TemplateContent, markDirty?: boolean) => void;
|
|
301
|
+
markDirty: () => void;
|
|
302
|
+
}
|
|
303
|
+
/** Something to tell the person at this editor. */
|
|
304
|
+
type CollaborationNotice =
|
|
305
|
+
/** Someone else holds the block this session tried to select. */
|
|
306
|
+
{
|
|
307
|
+
type: "selectionRefused";
|
|
308
|
+
blockId: string;
|
|
309
|
+
holder: BlockLockHolder;
|
|
310
|
+
} |
|
|
311
|
+
/** A local change was refused and taken back. */
|
|
312
|
+
{
|
|
313
|
+
type: "editRefused";
|
|
314
|
+
code: CollaborationConflictCode;
|
|
315
|
+
holder?: BlockLockHolder;
|
|
316
|
+
} |
|
|
317
|
+
/** An undo or redo step no longer applies and was dropped. */
|
|
318
|
+
{
|
|
319
|
+
type: "undoSkipped";
|
|
320
|
+
code: CollaborationConflictCode;
|
|
321
|
+
};
|
|
322
|
+
/** A re-sync another session caused, as the backend announced it. */
|
|
323
|
+
interface CollaborationRemoteResync {
|
|
324
|
+
/** The revision the re-sync brings the template to. */
|
|
325
|
+
revision: number;
|
|
326
|
+
actor: CollaborationActor;
|
|
327
|
+
}
|
|
328
|
+
interface UseCollaborationOptions {
|
|
329
|
+
provider: CollaborationProvider;
|
|
330
|
+
/**
|
|
331
|
+
* Fetch a template when the backend says to re-sync: the templates
|
|
332
|
+
* provider's `load`. Its `revision` says which revision `content` is at.
|
|
333
|
+
*/
|
|
334
|
+
loadTemplate: (templateId: string) => Promise<Template>;
|
|
335
|
+
/** This editor instance's session id. A new UUID when omitted. */
|
|
336
|
+
sessionId?: string;
|
|
337
|
+
/** How many undo steps to keep. */
|
|
338
|
+
maxUndo?: number;
|
|
339
|
+
/** A batch from another session was applied. */
|
|
340
|
+
onRemoteChange?: (change: CollaborationRemoteChange) => void;
|
|
341
|
+
/**
|
|
342
|
+
* Another session re-synced the template — a `setContent`, a restore, a
|
|
343
|
+
* batch too large to broadcast — and the backend said who. Called for a
|
|
344
|
+
* revision this session doesn't have yet, before it catches up; the
|
|
345
|
+
* catch-up's batches still reach `onRemoteChange`. The editor names an
|
|
346
|
+
* agent's re-sync with it.
|
|
347
|
+
*/
|
|
348
|
+
onRemoteResync?: (resync: CollaborationRemoteResync) => void;
|
|
349
|
+
/**
|
|
350
|
+
* Rewrite another session's batch just before it is applied, given the
|
|
351
|
+
* content it applies to. Called for live batches and catch-up batches
|
|
352
|
+
* alike, never for this session's own. The editor uses it to turn merge-tag
|
|
353
|
+
* tokens into tags, as it does for loaded content. `onRemoteChange` still
|
|
354
|
+
* receives the batch as the backend sent it.
|
|
355
|
+
*/
|
|
356
|
+
normalizeRemoteOperations?: (ops: readonly Operation[], content: TemplateContent) => Operation[];
|
|
357
|
+
onNotice?: (notice: CollaborationNotice) => void;
|
|
358
|
+
onError?: (error: Error) => void;
|
|
359
|
+
}
|
|
360
|
+
interface UseCollaborationReturn {
|
|
361
|
+
readonly sessionId: string;
|
|
362
|
+
/** Everyone with the template open, this session included; empty without presence. */
|
|
363
|
+
members: Readonly<Ref<readonly CollaborationMember[]>>;
|
|
364
|
+
/** Blocks other sessions hold, by block id. */
|
|
365
|
+
locks: Readonly<Ref<ReadonlyMap<string, BlockLock>>>;
|
|
366
|
+
/** `null` before a realtime join, and for a backend without realtime. */
|
|
367
|
+
connection: Readonly<Ref<CollaborationConnectionState | null>>;
|
|
368
|
+
/** The last revision this session confirmed. */
|
|
369
|
+
revision: Readonly<Ref<number>>;
|
|
370
|
+
canUndo: ComputedRef<boolean>;
|
|
371
|
+
canRedo: ComputedRef<boolean>;
|
|
372
|
+
/** Wire the controller to the editor. Call once, inside the editor's setup scope. */
|
|
373
|
+
attach: (editor: CollaborationEditor) => void;
|
|
374
|
+
undo: () => void;
|
|
375
|
+
redo: () => void;
|
|
376
|
+
clearHistory: () => void;
|
|
377
|
+
/** Turn edits not sent yet into a batch now. */
|
|
378
|
+
flush: () => void;
|
|
379
|
+
/** Resolves once every batch is confirmed; rejects when one fails in transit. */
|
|
380
|
+
settle: () => Promise<void>;
|
|
381
|
+
/** Stop reading the canvas (a version preview is on it). Batches keep arriving. */
|
|
382
|
+
suspend: () => void;
|
|
383
|
+
/** Put the current state back on the canvas and read it again. */
|
|
384
|
+
resume: () => void;
|
|
385
|
+
/** Fetch what this session missed, or reload when the backend says to. */
|
|
386
|
+
catchUp: () => Promise<void>;
|
|
387
|
+
/** Whether the block exists in the content the backend confirmed. */
|
|
388
|
+
hasConfirmedBlock: (blockId: string) => boolean;
|
|
389
|
+
destroy: () => void;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Real-time collaboration over a {@link CollaborationProvider}.
|
|
393
|
+
*
|
|
394
|
+
* The controller keeps the content the backend confirmed at revision R, plus
|
|
395
|
+
* this session's pending batches; the canvas shows the confirmed content with
|
|
396
|
+
* the pending batches applied. Local changes are captured by diffing the
|
|
397
|
+
* canvas against that view: structural changes, selection changes and blur
|
|
398
|
+
* send at once, typing into one block after a short pause. One batch is in
|
|
399
|
+
* flight at a time. Batches from other sessions apply strictly by revision,
|
|
400
|
+
* with this session's pending batches replayed on top; a gap that isn't
|
|
401
|
+
* filled within a second, a re-sync, a reconnect and a refusal all fetch what
|
|
402
|
+
* was missed.
|
|
403
|
+
*
|
|
404
|
+
* Selecting a block takes its lock (when the backend has locks), renewed
|
|
405
|
+
* while selected and released on deselect, template switch and page hide.
|
|
406
|
+
* Undo and redo send inverse batches guarded by preconditions; one that no
|
|
407
|
+
* longer applies is dropped with a notice. Changes from others never enter the
|
|
408
|
+
* stacks.
|
|
409
|
+
*/
|
|
410
|
+
export declare function useCollaboration(options: UseCollaborationOptions): UseCollaborationReturn;
|
|
411
|
+
//#endregion
|
|
144
412
|
//#region src/saved-blocks.d.ts
|
|
145
413
|
interface UseSavedBlocksOptions {
|
|
146
414
|
/**
|
|
@@ -419,5 +687,5 @@ interface UseCommentListenerOptions {
|
|
|
419
687
|
*/
|
|
420
688
|
export declare function useCommentListener(options: UseCommentListenerOptions): void;
|
|
421
689
|
//#endregion
|
|
422
|
-
export {
|
|
690
|
+
export type { CollaborationEditor, CollaborationNotice, CollaborationRemoteResync, CollaborationTemplate, EditorState, LocalStorageMediaProviderOptions, LocalStorageSavedBlocksOptions, UseAutoSaveOptions, UseAutoSaveReturn, UseBlockActionsOptions, UseBlockActionsReturn, UseCollaborationOptions, UseCollaborationReturn, UseCommentListenerOptions, UseCommentsOptions, UseCommentsReturn, UseConditionPreviewReturn, UseEditorOptions, UseEditorReturn, UseHistoryOptions, UseHistoryReturn, UseSavedBlocksOptions, UseSavedBlocksReturn, UseVersionHistoryOptions, UseVersionHistoryReturn };
|
|
423
691
|
//# sourceMappingURL=index.d.ts.map
|