@templatical/core 0.26.3 → 0.27.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.
@@ -0,0 +1,99 @@
1
+ import { Block, Template, TemplateContent, TemplateDefaults, TemplateSettings, TemplatesProvider, UiTheme, ViewportSize } from "@templatical/types";
2
+ import { DeepReadonly, Ref } from "@vue/reactivity";
3
+ //#region src/editor.d.ts
4
+ interface EditorState {
5
+ /**
6
+ * The template currently being edited, as the store last returned it — `null`
7
+ * until `create()` or `load()` resolves, and always `null` without a
8
+ * {@link TemplatesProvider}.
9
+ *
10
+ * Carries identity and name only for practical purposes: its `content` is the
11
+ * store's copy from the last round-trip, whereas `state.content` is what the
12
+ * user is editing.
13
+ */
14
+ template: Template | null;
15
+ content: TemplateContent;
16
+ selectedBlockId: string | null;
17
+ viewport: ViewportSize;
18
+ darkMode: boolean;
19
+ previewMode: boolean;
20
+ isDirty: boolean;
21
+ /** True for the duration of a `save()` call. */
22
+ isSaving: boolean;
23
+ /** True for the duration of a `create()` or `load()` call. */
24
+ isLoading: boolean;
25
+ uiTheme: UiTheme;
26
+ }
27
+ interface UseEditorOptions {
28
+ content: TemplateContent;
29
+ defaultFontFamily?: string;
30
+ templateDefaults?: TemplateDefaults;
31
+ lockedBlocks?: Ref<Map<string, unknown>>;
32
+ /**
33
+ * Storage backend for the template's save/load lifecycle. Omit it and
34
+ * `create()` / `load()` / `save()` reject — the editor keeps working as a
35
+ * purely local editing surface.
36
+ */
37
+ templates?: TemplatesProvider;
38
+ /**
39
+ * Called with any error a provider call rejects with, before the rejection is
40
+ * re-thrown to the caller.
41
+ */
42
+ onError?: (error: Error) => void;
43
+ }
44
+ interface UseEditorReturn {
45
+ state: DeepReadonly<EditorState>;
46
+ content: Ref<TemplateContent>;
47
+ selectedBlock: Ref<Block | null>;
48
+ setContent: (content: TemplateContent, markDirty?: boolean) => void;
49
+ selectBlock: (blockId: string | null) => void;
50
+ setViewport: (viewport: ViewportSize) => void;
51
+ setDarkMode: (darkMode: boolean) => void;
52
+ setPreviewMode: (previewMode: boolean) => void;
53
+ setUiTheme: (theme: UiTheme) => void;
54
+ updateBlock: (blockId: string, updates: Partial<Block>) => void;
55
+ updateSettings: (updates: Partial<TemplateSettings>) => void;
56
+ addBlock: (block: Block, targetSectionId?: string, columnIndex?: number, index?: number) => void;
57
+ removeBlock: (blockId: string) => void;
58
+ moveBlock: (blockId: string, newIndex: number, targetSectionId?: string, columnIndex?: number) => void;
59
+ isBlockLocked: (blockId: string) => boolean;
60
+ markDirty: () => void;
61
+ findBlockLocation: (blockId: string) => {
62
+ targetSectionId?: string;
63
+ columnIndex?: number;
64
+ index: number;
65
+ } | null;
66
+ /**
67
+ * Rename the loaded template locally and mark the editor dirty. The new name
68
+ * reaches the store on the next `save()`, in the same patch as the content —
69
+ * a rename is an ordinary unsaved change, not a side channel.
70
+ *
71
+ * This method only stages it. The editor's inline rename field commits by
72
+ * calling `setName()` and then saving immediately, because a rename reads as a
73
+ * discrete action rather than an edit to be batched — so in the editor the
74
+ * "next `save()`" is usually the one it triggers itself. A headless caller
75
+ * decides its own moment.
76
+ *
77
+ * No-op when no template is loaded: there is nothing to name.
78
+ */
79
+ setName: (name: string) => void;
80
+ /**
81
+ * Persist the current content as a new template. `input.content`, when given,
82
+ * replaces the editor's content first — so `create({ content })` both loads
83
+ * and stores in one step.
84
+ */
85
+ create: (input?: {
86
+ name?: string;
87
+ content?: TemplateContent;
88
+ }) => Promise<Template>;
89
+ /** Fetch a template and make it the editor's content. */
90
+ load: (templateId: string) => Promise<Template>;
91
+ /** Persist the loaded template's name + content as a patch. */
92
+ save: () => Promise<Template>;
93
+ /** Whether a template has been created or loaded. */
94
+ hasTemplate: () => boolean;
95
+ }
96
+ declare function useEditor(options: UseEditorOptions): UseEditorReturn;
97
+ //#endregion
98
+ export { useEditor as i, UseEditorOptions as n, UseEditorReturn as r, EditorState as t };
99
+ //# sourceMappingURL=editor-BCujEIye.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { i as useEditor, n as UseEditorOptions, r as UseEditorReturn, t as EditorState } from "./editor-BIIsaIoN.js";
2
- import { Block, BlockDefaults, BlockType, CustomBlock, CustomBlockDefinition, SavedBlock, SavedBlockPatch, SavedBlocksListParams, SavedBlocksProvider, TemplateContent } from "@templatical/types";
1
+ import { i as useEditor, n as UseEditorOptions, r as UseEditorReturn, t as EditorState } from "./editor-BCujEIye.js";
2
+ import { Block, BlockDefaults, BlockType, Comment, CommentAuthor, CommentEvent, CommentInput, CommentPatch, CommentsListParams, CommentsProvider, CustomBlock, CustomBlockDefinition, SavedBlock, SavedBlockPatch, SavedBlocksListParams, SavedBlocksProvider, Template, TemplateContent, TemplateSettings, TemplateVersion, VersionHistoryListParams, VersionHistoryProvider } from "@templatical/types";
3
3
  import { ComputedRef, Ref } from "@vue/reactivity";
4
4
  import { ComputedRef as ComputedRef$1, Ref as Ref$1 } from "vue";
5
5
  //#region src/history.d.ts
@@ -60,6 +60,21 @@ interface UseAutoSaveReturn {
60
60
  resume: () => void;
61
61
  destroy: () => void;
62
62
  }
63
+ /**
64
+ * Trailing debounce, in ms, measured from the *last* content mutation.
65
+ *
66
+ * Typing is not debounced upstream — TipTap's `onUpdate` calls `updateBlock` per
67
+ * keystroke — so this is the only thing between a keypress and a whole-document
68
+ * write. 1000 was too eager: ordinary prose pauses for a second constantly
69
+ * (word choice, re-reading, reaching for the mouse), so a single paragraph could
70
+ * produce dozens of full-content saves. 2000 roughly halves that while still
71
+ * landing well before a user wonders whether their work was kept.
72
+ *
73
+ * **The single default for both entry points.** `initCloud()` used to carry its
74
+ * own copy at 5000 in the editor package; two constants for one setting drifted
75
+ * silently and nothing linked them. Cloud imports this one now.
76
+ */
77
+ declare const DEFAULT_AUTO_SAVE_DEBOUNCE_MS = 2000;
63
78
  declare function useAutoSave(options: UseAutoSaveOptions): UseAutoSaveReturn;
64
79
  //#endregion
65
80
  //#region src/condition-preview.d.ts
@@ -69,7 +84,18 @@ interface UseConditionPreviewReturn {
69
84
  reset: () => void;
70
85
  hasHiddenBlocks: ComputedRef<boolean>;
71
86
  }
72
- declare function useConditionPreview(editor: UseEditorReturn): UseConditionPreviewReturn;
87
+ /**
88
+ * The slice of an editor this needs — deliberately structural, so both the OSS
89
+ * and the Cloud `useEditor` satisfy it without either having to grow toward the
90
+ * other.
91
+ */
92
+ interface ConditionPreviewEditor {
93
+ state: {
94
+ readonly selectedBlockId: string | null;
95
+ };
96
+ selectBlock: (blockId: string | null) => void;
97
+ }
98
+ declare function useConditionPreview(editor: ConditionPreviewEditor): UseConditionPreviewReturn;
73
99
  //#endregion
74
100
  //#region src/data-source-fetch.d.ts
75
101
  declare function useDataSourceFetch(options: {
@@ -85,6 +111,19 @@ declare function useDataSourceFetch(options: {
85
111
  };
86
112
  //#endregion
87
113
  //#region src/history-interceptor.d.ts
114
+ /**
115
+ * The mutable slice of an editor this wraps — structural, so the OSS and Cloud
116
+ * `useEditor` returns both satisfy it without either having to grow toward the
117
+ * other. Not `Readonly`: the whole point is to replace these members in place.
118
+ */
119
+ interface HistoryInterceptorEditor {
120
+ addBlock: (block: Block, targetSectionId?: string, columnIndex?: number, index?: number) => void;
121
+ removeBlock: (blockId: string) => void;
122
+ moveBlock: (blockId: string, newIndex: number, targetSectionId?: string, columnIndex?: number) => void;
123
+ updateBlock: (blockId: string, updates: Partial<Block>) => void;
124
+ updateSettings: (updates: Partial<TemplateSettings>) => void;
125
+ isBlockLocked: (blockId: string) => boolean;
126
+ }
88
127
  /**
89
128
  * Wraps editor mutation methods to record history snapshots before each
90
129
  * operation. Mutates the editor object in place.
@@ -92,7 +131,7 @@ declare function useDataSourceFetch(options: {
92
131
  * Must be applied **after** any collaboration broadcast wrapping so the
93
132
  * call chain is: history.record() → broadcast → original mutation.
94
133
  */
95
- declare function useHistoryInterceptor(editor: UseEditorReturn, history: UseHistoryReturn): void;
134
+ declare function useHistoryInterceptor(editor: HistoryInterceptorEditor, history: UseHistoryReturn): void;
96
135
  //#endregion
97
136
  //#region src/saved-blocks.d.ts
98
137
  interface UseSavedBlocksOptions {
@@ -184,5 +223,170 @@ interface LocalStorageSavedBlocksOptions {
184
223
  */
185
224
  declare function createLocalStorageSavedBlocksProvider(options?: LocalStorageSavedBlocksOptions): SavedBlocksProvider;
186
225
  //#endregion
187
- export { type EditorState, type LocalStorageSavedBlocksOptions, type UseAutoSaveOptions, type UseAutoSaveReturn, type UseBlockActionsOptions, type UseBlockActionsReturn, type UseConditionPreviewReturn, type UseEditorOptions, type UseEditorReturn, type UseHistoryOptions, type UseHistoryReturn, type UseSavedBlocksOptions, type UseSavedBlocksReturn, createLocalStorageSavedBlocksProvider, useAutoSave, useBlockActions, useConditionPreview, useDataSourceFetch, useEditor, useHistory, useHistoryInterceptor, useSavedBlocks };
226
+ //#region src/version-history.d.ts
227
+ interface UseVersionHistoryOptions {
228
+ /**
229
+ * Storage backend. Supplied by the consumer via `init({ versionHistory })`,
230
+ * or by Cloud's own adapter — this composable is transport-agnostic and never
231
+ * talks to a network itself.
232
+ */
233
+ provider: VersionHistoryProvider;
234
+ /**
235
+ * Which template's history this is. A getter rather than a value because a
236
+ * session can outlive the template: `initCloud()` constructs the feature at
237
+ * setup and only learns the id once `create()` / `load()` resolves.
238
+ */
239
+ getTemplateId: () => string | null;
240
+ onError?: (error: Error) => void;
241
+ }
242
+ interface UseVersionHistoryReturn {
243
+ /** The provider's list, in the provider's order. Never re-sorted. */
244
+ versions: Ref$1<TemplateVersion[]>;
245
+ isLoading: Ref$1<boolean>;
246
+ isRestoring: Ref$1<boolean>;
247
+ /**
248
+ * Cursor for the page after the one currently held, or `undefined` when the
249
+ * provider signalled there is no more. The editor loads one page and ignores
250
+ * this; it is here so a headless caller can page without reaching past the
251
+ * composable.
252
+ */
253
+ nextCursor: Ref$1<string | undefined>;
254
+ /** Whether the provider supplied each mutation at all. */
255
+ canCreate: ComputedRef$1<boolean>;
256
+ canRestore: ComputedRef$1<boolean>;
257
+ /** Re-read the list. The editor calls this bare; `params` is for headless callers. */
258
+ load: (params?: VersionHistoryListParams) => Promise<void>;
259
+ /**
260
+ * The version's content **if it is already in hand** — the provider's
261
+ * `content` hint, or a previous `get` this composable cached. `null` means a
262
+ * round-trip is required.
263
+ *
264
+ * Callers that must not block (scrubbing through history swaps the canvas in
265
+ * the same tick) check this first and only await {@link resolveContent} when
266
+ * it comes back null.
267
+ */
268
+ peekContent: (version: TemplateVersion) => TemplateContent | null;
269
+ /**
270
+ * `version.content ?? await provider.get(...)`, cached per version id, so a
271
+ * lazily-loaded version costs one round-trip on its first visit and nothing
272
+ * afterwards.
273
+ */
274
+ resolveContent: (version: TemplateVersion) => Promise<TemplateContent>;
275
+ /** Rejects with an {@link SdkError} when the provider disabled `create`. */
276
+ create: (content: TemplateContent, meta?: {
277
+ label?: string;
278
+ }) => Promise<TemplateVersion>;
279
+ /** Rejects with an {@link SdkError} when the provider disabled `restore`. */
280
+ restore: (versionId: string) => Promise<Template>;
281
+ }
282
+ /**
283
+ * Reactive state over a {@link VersionHistoryProvider}.
284
+ *
285
+ * Owns the list, the loading flags and the per-version content cache that keeps
286
+ * scrubbing synchronous. Errors are reported through `onError` and re-thrown,
287
+ * leaving the list untouched on failure.
288
+ *
289
+ * It deliberately does **not** create versions of its own accord. The editor
290
+ * never records a version on a save — whoever implements `TemplatesProvider.save`
291
+ * decides that, because they are the side that pays for the storage.
292
+ */
293
+ declare function useVersionHistory(options: UseVersionHistoryOptions): UseVersionHistoryReturn;
294
+ //#endregion
295
+ //#region src/comments.d.ts
296
+ interface UseCommentsOptions {
297
+ /**
298
+ * Storage backend. Supplied by the consumer via `init({ comments })`, or by
299
+ * Cloud's own adapter — this composable is transport-agnostic and never talks
300
+ * to a network itself.
301
+ */
302
+ provider: CommentsProvider;
303
+ /**
304
+ * Which template's conversation this is. A getter rather than a value because a
305
+ * session can outlive the template: `initCloud()` constructs the feature at
306
+ * setup and only learns the id once `create()` / `load()` resolves.
307
+ */
308
+ getTemplateId: () => string | null;
309
+ /**
310
+ * Who is commenting, read at call time. `null` means the editor has no
311
+ * identity, and every mutation refuses — an unattributable comment is worse
312
+ * than no comment feature.
313
+ */
314
+ getUser: () => CommentAuthor | null;
315
+ /** Fired for every change this composable applied, local or remote. */
316
+ onComment?: (event: CommentEvent) => void;
317
+ onError?: (error: Error) => void;
318
+ }
319
+ interface UseCommentsReturn {
320
+ /** Thread roots in the provider's order. Never re-sorted. */
321
+ comments: Ref$1<Comment[]>;
322
+ isLoading: Ref$1<boolean>;
323
+ isSubmitting: Ref$1<boolean>;
324
+ /** Whether the provider supplied each mutation at all. */
325
+ canCreate: ComputedRef$1<boolean>;
326
+ canUpdate: ComputedRef$1<boolean>;
327
+ canDelete: ComputedRef$1<boolean>;
328
+ canResolve: ComputedRef$1<boolean>;
329
+ /** Roots plus replies. */
330
+ totalCount: ComputedRef$1<number>;
331
+ /** Unresolved roots — the badge on the trigger. */
332
+ unresolvedCount: ComputedRef$1<number>;
333
+ /** Comments per anchored block id, roots plus their replies. */
334
+ commentCountByBlock: ComputedRef$1<Map<string, number>>;
335
+ /** Re-read the list. The editor calls this bare; `params` is for headless callers. */
336
+ load: (params?: CommentsListParams) => Promise<void>;
337
+ /** Rejects with an {@link SdkError} when `create` is disabled or there is no user. */
338
+ create: (input: CommentInput) => Promise<Comment>;
339
+ /** Rejects with an {@link SdkError} when `update` is disabled or there is no user. */
340
+ update: (commentId: string, patch: CommentPatch) => Promise<Comment>;
341
+ /** Rejects with an {@link SdkError} when `delete` is disabled or there is no user. */
342
+ remove: (commentId: string) => Promise<void>;
343
+ /** Rejects with an {@link SdkError} when `setResolved` is disabled or there is no user. */
344
+ setResolved: (commentId: string, resolved: boolean) => Promise<Comment>;
345
+ /** Look one up by id, root or reply. `null` when it isn't loaded. */
346
+ find: (commentId: string) => Comment | null;
347
+ /** Whether this comment was written by the current user. */
348
+ isOwn: (comment: Comment) => boolean;
349
+ /**
350
+ * Apply a change that arrived from {@link CommentsProvider.subscribe}. Public
351
+ * so a consumer driving this headlessly can push their own transport into it.
352
+ */
353
+ applyRemoteCreate: (comment: Comment) => void;
354
+ applyRemoteUpdate: (comment: Comment) => void;
355
+ applyRemoteDelete: (commentId: string, parentId?: string | null) => void;
356
+ }
357
+ /**
358
+ * Reactive state over a {@link CommentsProvider}.
359
+ *
360
+ * Owns the thread list, the loading flags, the local mutations that keep the list
361
+ * consistent, and the derived counts the chrome renders. Errors are reported
362
+ * through `onError` and **re-thrown**, leaving the list untouched on failure —
363
+ * the same discipline as `useSavedBlocks` and `useVersionHistory`.
364
+ *
365
+ * Mutations **reject** when the provider withheld them rather than resolving to
366
+ * `null`: a resolved promise reads as "saved" to whoever awaited it. Ask through
367
+ * `canCreate` / `canUpdate` / `canDelete` / `canResolve` first — which is what the
368
+ * editor's own UI does, hiding each action rather than disabling it.
369
+ */
370
+ declare function useComments(options: UseCommentsOptions): UseCommentsReturn;
371
+ interface UseCommentListenerOptions {
372
+ comments: UseCommentsReturn;
373
+ provider: CommentsProvider;
374
+ getTemplateId: () => string | null;
375
+ }
376
+ /**
377
+ * Wire {@link CommentsProvider.subscribe} into the three `applyRemote*` paths.
378
+ *
379
+ * A no-op when the provider has no `subscribe` — realtime is optional, and
380
+ * comments without it work exactly the same except that a colleague's comment
381
+ * only appears on the next read. Nothing here knows about a transport: Cloud's
382
+ * Pusher channel lives inside `createCloudCommentsProvider`, and an SSE or
383
+ * long-poll implementation is the same three lines on the consumer's side.
384
+ *
385
+ * Re-subscribes when the template id changes, and unsubscribes on scope dispose —
386
+ * so a session that loads a second template does not keep receiving the first
387
+ * one's comments.
388
+ */
389
+ declare function useCommentListener(options: UseCommentListenerOptions): void;
390
+ //#endregion
391
+ export { DEFAULT_AUTO_SAVE_DEBOUNCE_MS, type EditorState, type LocalStorageSavedBlocksOptions, type UseAutoSaveOptions, type UseAutoSaveReturn, type UseBlockActionsOptions, type UseBlockActionsReturn, type UseCommentListenerOptions, type UseCommentsOptions, type UseCommentsReturn, type UseConditionPreviewReturn, type UseEditorOptions, type UseEditorReturn, type UseHistoryOptions, type UseHistoryReturn, type UseSavedBlocksOptions, type UseSavedBlocksReturn, type UseVersionHistoryOptions, type UseVersionHistoryReturn, createLocalStorageSavedBlocksProvider, useAutoSave, useBlockActions, useCommentListener, useComments, useConditionPreview, useDataSourceFetch, useEditor, useHistory, useHistoryInterceptor, useSavedBlocks, useVersionHistory };
188
392
  //# sourceMappingURL=index.d.ts.map