@bloklabs/angular 1.15.1 → 1.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/fesm2022/bloklabs-angular.mjs +1872 -4131
- package/fesm2022/bloklabs-angular.mjs.map +1 -1
- package/package.json +2 -2
- package/types/bloklabs-angular.d.ts +1678 -811
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import * as i0 from
|
|
2
|
-
import { AfterViewInit, DoCheck,
|
|
3
|
-
import { ControlValueAccessor } from
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { AfterViewInit, DoCheck, ElementRef, EnvironmentProviders, EventEmitter, InjectionToken, OnDestroy, Signal, Type } from "@angular/core";
|
|
3
|
+
import { ControlValueAccessor } from "@angular/forms";
|
|
4
|
+
import { API, BlockAPI, BlockMutationEvent, BlockOrigin, BlockPosition, BlockRenderedPayload, BlockToolConstructable, BlockToolConstructorOptions, BlockToolData, BlockTuneData, BlocksRenderedPayload, Blok, BlokConfig, EditorWidth, LooseOutputBlockData, LooseOutputData, MarkdownImportConfig, OutputBlockData, OutputData, ReadOnlyModeConfig, ResolvedTheme, ThemeMode, ToolboxConfig } from "@bloklabs/core";
|
|
6
5
|
/**
|
|
7
6
|
* Configuration for the Angular adapter. Same as `BlokConfig` but without
|
|
8
7
|
* `holder` (the adapter owns the host element), plus the reactive `width` prop.
|
|
9
8
|
* Mirrors the React adapter's `UseBlokConfig`.
|
|
10
9
|
*/
|
|
11
10
|
type BlokAngularConfig = Omit<BlokConfig, 'holder'> & {
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
/** Editor content width mode. Synced reactively after mount via `editor.width.set()`. */
|
|
12
|
+
width?: EditorWidth;
|
|
14
13
|
};
|
|
15
|
-
|
|
16
14
|
/**
|
|
17
15
|
* The blessed all-in-one Angular component for embedding Blok (mirrors React's
|
|
18
16
|
* `BlokEditor`). Delegates instance lifecycle to an internal `BlokContentDirective`
|
|
@@ -35,227 +33,343 @@ type BlokAngularConfig = Omit<BlokConfig, 'holder'> & {
|
|
|
35
33
|
* `BlokContentDirective`. Each reactive input is backed by an internal `signal`
|
|
36
34
|
* so effect-based syncing still works; the public template API is unchanged.
|
|
37
35
|
*/
|
|
38
|
-
declare class BlokEditorComponent implements AfterViewInit, DoCheck, ControlValueAccessor {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
36
|
+
export declare class BlokEditorComponent implements AfterViewInit, DoCheck, OnDestroy, ControlValueAccessor {
|
|
37
|
+
private readonly ngZone;
|
|
38
|
+
/** App-wide defaults from `provideBlok()`; merged UNDER per-instance inputs. */
|
|
39
|
+
private readonly defaults;
|
|
40
|
+
private contentQuery?;
|
|
41
|
+
/** Signal bridge for the @ViewChild directive so effects react to its arrival. */
|
|
42
|
+
private readonly content;
|
|
43
|
+
/**
|
|
44
|
+
* Output half of two-way `[(data)]`. Emits the editor's serialized content on
|
|
45
|
+
* every change. Wiring the core `onSave` callback is gated on this being
|
|
46
|
+
* observed, since its mere presence makes the core serialize on every batch.
|
|
47
|
+
*/
|
|
48
|
+
/** Emits the live Blok instance once ready, after `instance()` is populated. */
|
|
49
|
+
readonly ready: EventEmitter<Blok>;
|
|
50
|
+
readonly dataChange: EventEmitter<OutputData>;
|
|
51
|
+
/** Fires with the full serialized content on every change (notification half). */
|
|
52
|
+
readonly save: EventEmitter<OutputData>;
|
|
53
|
+
/** Raw block mutation channel (core `onChange`). */
|
|
54
|
+
readonly change: EventEmitter<{
|
|
55
|
+
api: API;
|
|
56
|
+
event: BlockMutationEvent | BlockMutationEvent[];
|
|
57
|
+
}>;
|
|
58
|
+
/** Fires after the editor finishes (re-)rendering (core `onAfterRender`). */
|
|
59
|
+
readonly afterRender: EventEmitter<API>;
|
|
60
|
+
/** Fires with the resolved theme whenever it changes (core `onThemeChange`). */
|
|
61
|
+
readonly themeChange: EventEmitter<ResolvedTheme>;
|
|
62
|
+
/** Fires after a batch render completes (core `blocks:rendered` event). */
|
|
63
|
+
readonly blocksRendered: EventEmitter<BlocksRenderedPayload>;
|
|
64
|
+
/** Fires for each block rendered into the DOM (core `block:rendered` event). */
|
|
65
|
+
readonly blockRendered: EventEmitter<BlockRenderedPayload>;
|
|
66
|
+
/**
|
|
67
|
+
* Transform hook applied to blocks before render (core `onBeforeRender`). Must
|
|
68
|
+
* return the (possibly modified) block list. An input, not an output, because
|
|
69
|
+
* it returns a value.
|
|
70
|
+
*/
|
|
71
|
+
onBeforeRender?: (blocks: OutputBlockData[]) => OutputBlockData[];
|
|
72
|
+
/**
|
|
73
|
+
* Transform hook applied to pasted HTML (core `onBeforePaste`). Returns the
|
|
74
|
+
* (possibly modified) html, or null to drop the paste.
|
|
75
|
+
*/
|
|
76
|
+
onBeforePaste?: (html: string) => string | null;
|
|
77
|
+
/**
|
|
78
|
+
* Error channel (core `onError`). Fires with the raised error whenever an
|
|
79
|
+
* editor operation — currently serialization — fails instead of only logging.
|
|
80
|
+
*/
|
|
81
|
+
onError?: BlokConfig['onError'];
|
|
82
|
+
/**
|
|
83
|
+
* Failed-image channel (core `onImageFailure`). Return false to replace blok's own notice.
|
|
84
|
+
*/
|
|
85
|
+
onImageFailure?: BlokConfig['onImageFailure'];
|
|
86
|
+
private readonly readOnly$;
|
|
87
|
+
set readOnly(value: BlokConfig['readOnly'] | undefined);
|
|
88
|
+
private readonly hideToolbar$;
|
|
89
|
+
set hideToolbar(value: boolean | undefined);
|
|
90
|
+
private readonly toolbarPosition$;
|
|
91
|
+
set toolbarPosition(value: BlokConfig['toolbarPosition'] | undefined);
|
|
92
|
+
private readonly inlineToolbar$;
|
|
93
|
+
set inlineToolbar(value: boolean | string[] | undefined);
|
|
94
|
+
private readonly theme$;
|
|
95
|
+
set theme(value: ThemeMode | undefined);
|
|
96
|
+
private readonly width$;
|
|
97
|
+
set width(value: EditorWidth | undefined);
|
|
98
|
+
private readonly placeholder$;
|
|
99
|
+
set placeholder(value: string | false | undefined);
|
|
100
|
+
/**
|
|
101
|
+
* Theme tokens. Construction-only config forced hosts with a live light/dark
|
|
102
|
+
* toggle to recreate the editor or hand-write the global stylesheet Blok
|
|
103
|
+
* already injects; this drives the runtime `tokens` API instead.
|
|
104
|
+
*/
|
|
105
|
+
private readonly styleTokens$;
|
|
106
|
+
set styleTokens(value: Record<string, string> | undefined);
|
|
107
|
+
/**
|
|
108
|
+
* Locale, host message overrides and text direction. `config.i18n` was
|
|
109
|
+
* consumed once at boot, so a host driving a language switcher had to
|
|
110
|
+
* recreate the editor (losing caret, focus and undo stack) to relabel the
|
|
111
|
+
* UI; this drives the runtime `i18n.update` API instead. `defaultLocale` is
|
|
112
|
+
* not forwarded — it only affects the INITIAL locale resolution.
|
|
113
|
+
*/
|
|
114
|
+
private readonly i18n$;
|
|
115
|
+
set i18n(value: BlokConfig['i18n'] | undefined);
|
|
116
|
+
private readonly autofocus$;
|
|
117
|
+
set autofocus(value: boolean | undefined);
|
|
118
|
+
private readonly data$;
|
|
119
|
+
set data(value: OutputData | LooseOutputData | null | undefined);
|
|
120
|
+
tools?: BlokConfig['tools'];
|
|
121
|
+
/** Host-supplied per-type block migrations applied at load (merged across layers). */
|
|
122
|
+
migrations?: BlokConfig['migrations'];
|
|
123
|
+
/**
|
|
124
|
+
* Escape hatch: a full config object for keys without a dedicated input
|
|
125
|
+
* (sanitizer, minHeight, …). Layered between provideBlok
|
|
126
|
+
* defaults and the discrete inputs.
|
|
127
|
+
*/
|
|
128
|
+
config?: Partial<BlokAngularConfig>;
|
|
129
|
+
/** Changing this input's identity destroys and recreates the editor (≙ React `deps`). */
|
|
130
|
+
recreateKey: unknown;
|
|
131
|
+
/**
|
|
132
|
+
* Content the editor currently reflects. Set when seeded, when the data effect
|
|
133
|
+
* renders, when the editor emits its own output (`coreOnSave`) and when the
|
|
134
|
+
* imperative `render()` facade lands. A controlled `data` echo that
|
|
135
|
+
* content-equals this baseline is a no-op, so it won't clobber the caret.
|
|
136
|
+
* Renders are serialized via `renderChain`. `undefined` means "nothing recorded
|
|
137
|
+
* yet" — never an empty document.
|
|
138
|
+
*/
|
|
139
|
+
private lastRenderedData?;
|
|
140
|
+
/**
|
|
141
|
+
* Content of the render currently queued or in flight — distinct from
|
|
142
|
+
* `lastRenderedData`, which names the last SUCCESSFUL one. The data effect
|
|
143
|
+
* dedupes against both, so an echo arriving mid-render is suppressed without
|
|
144
|
+
* the baseline having to move before the render resolves (a failed render
|
|
145
|
+
* would then strand it on content the editor never showed, and the host's
|
|
146
|
+
* retry of that same content would be deduped away forever).
|
|
147
|
+
* `undefined` means "nothing in flight".
|
|
148
|
+
*/
|
|
149
|
+
private pendingData?;
|
|
150
|
+
/**
|
|
151
|
+
* Window of recently emitted `onSave` payloads. `lastRenderedData` remembers
|
|
152
|
+
* only the LAST one, but a host that persists on save and refetches can echo
|
|
153
|
+
* an EARLIER save back after a newer one already replaced the baseline (the
|
|
154
|
+
* user kept typing). That stale echo is still the editor's own output, and
|
|
155
|
+
* rendering it is a whole-document replace — it would drop every character
|
|
156
|
+
* typed between the two saves and hand the rewound document to the next save,
|
|
157
|
+
* making the loss permanent in the host's store. Every `[data]` path funnels
|
|
158
|
+
* through the `data$` signal (the template input AND `writeValue`), so the one
|
|
159
|
+
* check in the data effect covers `patchValue` / `setValue` / `reset` too.
|
|
160
|
+
*/
|
|
161
|
+
private readonly emittedEcho;
|
|
162
|
+
/** Last token set pushed through `tokens.set`, for deep-equal deduping. */
|
|
163
|
+
private appliedTokens?;
|
|
164
|
+
/** Last i18n config pushed through `i18n.update`, for deep-equal deduping. */
|
|
165
|
+
private appliedI18n?;
|
|
166
|
+
/** Editor instance the i18n baseline above belongs to. */
|
|
167
|
+
private i18nAppliedFor;
|
|
168
|
+
/** Last value pushed through `tools.setInlineToolbar`, for content-compare deduping. */
|
|
169
|
+
private appliedInlineToolbar?;
|
|
170
|
+
private seededEditor;
|
|
171
|
+
private renderChain;
|
|
172
|
+
/**
|
|
173
|
+
* Editor the single collaboration warning has already been emitted for. Keyed
|
|
174
|
+
* by the editor, not a boolean, so the editor a `recreateKey` bump creates
|
|
175
|
+
* warns on its own first ignored `data` change instead of inheriting the
|
|
176
|
+
* previous editor's "already warned" flag and going silent.
|
|
177
|
+
*/
|
|
178
|
+
private collaborationWarnedFor;
|
|
179
|
+
/** Registered by `ControlValueAccessor.registerOnChange` (Angular forms). */
|
|
180
|
+
private cvaOnChange?;
|
|
181
|
+
private cvaOnTouched?;
|
|
182
|
+
/**
|
|
183
|
+
* Core `onSave` wrapper. Records the editor's own serialized output as the
|
|
184
|
+
* rendered baseline BEFORE notifying Angular, so a controlled consumer echoing
|
|
185
|
+
* it straight back into `data` deep-equals the baseline and is deduped to a
|
|
186
|
+
* no-op (no redundant render, no caret reset). Re-enters the Angular zone since
|
|
187
|
+
* the editor runs outside it.
|
|
188
|
+
*
|
|
189
|
+
* Falls back to an escape-hatch `[config]` callback when nothing Angular-side
|
|
190
|
+
* consumes the save — the baseline is recorded either way, so the controlled
|
|
191
|
+
* `data` dedupe works on both paths.
|
|
192
|
+
*/
|
|
193
|
+
private readonly coreOnSave;
|
|
194
|
+
/**
|
|
195
|
+
* Stable wrappers for the remaining live callbacks. Each resolves its target
|
|
196
|
+
* at call time (an observed output, else the `[config]` escape hatch), so a
|
|
197
|
+
* pushed handler never goes stale and only PRESENCE has to be synced.
|
|
198
|
+
*/
|
|
199
|
+
private readonly coreOnChange;
|
|
200
|
+
private readonly coreOnAfterRender;
|
|
201
|
+
private readonly coreOnBeforeRender;
|
|
202
|
+
private readonly coreOnEnter;
|
|
203
|
+
private readonly coreOnSubmit;
|
|
204
|
+
/** provideBlok defaults merged under the `[config]` escape hatch. */
|
|
205
|
+
private escapeHatchConfig;
|
|
206
|
+
/** True when an output, a two-way binding or Angular forms consumes `onSave`. */
|
|
207
|
+
private hasSaveConsumer;
|
|
208
|
+
/**
|
|
209
|
+
* The live callbacks this component currently wires into core, keyed by
|
|
210
|
+
* handler name — `undefined` for the ones nothing consumes.
|
|
211
|
+
*
|
|
212
|
+
* PRESENCE is the semantics in core (an `onSubmit` turns Enter into
|
|
213
|
+
* serialize-and-submit, an `onSave` arms the change-observation pipeline), so
|
|
214
|
+
* an unconsumed callback must stay absent. One source of truth for both the
|
|
215
|
+
* construction config and the runtime sync in `ngDoCheck`, so the two cannot
|
|
216
|
+
* drift.
|
|
217
|
+
* @returns the wrappers to install, `undefined` where nothing is wired
|
|
218
|
+
*/
|
|
219
|
+
private liveHandlers;
|
|
220
|
+
/** Handler presence installed on the live editor (the sync dedupe baseline). */
|
|
221
|
+
private appliedHandlers;
|
|
222
|
+
/** Live Blok instance, or null until `isReady` resolves / after destroy. */
|
|
223
|
+
readonly instance: import("@angular/core").Signal<Blok | null>;
|
|
224
|
+
/** Guards `ready` to one emission per editor instance. */
|
|
225
|
+
private lastReadyInstance;
|
|
226
|
+
/**
|
|
227
|
+
* Construction config handed to the directive. Seeds the editor's initial
|
|
228
|
+
* values; the directive only reads it once (at construction), so post-mount
|
|
229
|
+
* changes to construction-only inputs are no-ops by design.
|
|
230
|
+
*/
|
|
231
|
+
buildConfig(): Partial<BlokAngularConfig>;
|
|
232
|
+
ngAfterViewInit(): void;
|
|
233
|
+
/** Save consumers captured at destroy, for core's final save. */
|
|
234
|
+
private saveHandlersAtDestroy;
|
|
235
|
+
ngOnDestroy(): void;
|
|
236
|
+
/**
|
|
237
|
+
* Reactive callback presence.
|
|
238
|
+
*
|
|
239
|
+
* Callback wiring was decided once, at construction, and in core the presence
|
|
240
|
+
* of a handler IS the semantics: an `onSubmit` makes Enter serialize-and-submit
|
|
241
|
+
* instead of splitting the block, an `onSave` arms the whole change-observation
|
|
242
|
+
* pipeline. A `[config]` swap, an `*ngIf`-gated `(save)` output or a
|
|
243
|
+
* `registerOnChange` from Angular forms arriving after mount therefore needed a
|
|
244
|
+
* `recreateKey` bump — destroying the editor and losing caret and undo history.
|
|
245
|
+
*
|
|
246
|
+
* Diff the wired handlers against what is installed and push genuine flips
|
|
247
|
+
* through the runtime `handlers.set` API, writing `undefined` for a handler
|
|
248
|
+
* that lost its consumer so the change stays reversible. `ngDoCheck` (not an
|
|
249
|
+
* `effect`) because `EventEmitter.observed` and the plain `@Input` transforms
|
|
250
|
+
* are not signals; the comparison is six identity checks against stable
|
|
251
|
+
* wrappers, so an unchanged cycle pushes nothing.
|
|
252
|
+
*/
|
|
253
|
+
ngDoCheck(): void;
|
|
254
|
+
/** Serialize the current content. Resolves undefined until the editor is ready. */
|
|
255
|
+
save$(): Promise<OutputData> | undefined;
|
|
256
|
+
/** Ask before an in-app navigation (see `Blok.confirmLeave`). Resolves true until the editor is ready. */
|
|
257
|
+
confirmLeave(): Promise<boolean>;
|
|
258
|
+
/** Move the caret into the editor. */
|
|
259
|
+
focus(atEnd?: boolean): void;
|
|
260
|
+
/**
|
|
261
|
+
* Replace the editor content. Resolves undefined until the editor is ready.
|
|
262
|
+
*
|
|
263
|
+
* Safe to mix with a controlled `[data]` input: the rendered document becomes
|
|
264
|
+
* the content baseline once the call lands, so a later `[data]` change back to
|
|
265
|
+
* the previous document still re-renders instead of being deduped against a
|
|
266
|
+
* baseline the editor no longer reflects. Recorded only on the resolved path —
|
|
267
|
+
* a failed render leaves the editor on its previous content.
|
|
268
|
+
* @param data - the document to render
|
|
269
|
+
*/
|
|
270
|
+
render(data: OutputData | LooseOutputData): Promise<void> | undefined;
|
|
271
|
+
constructor();
|
|
272
|
+
/** Seeds/renders an externally-set form value through the same dedup machinery. */
|
|
273
|
+
writeValue(value: OutputData | LooseOutputData | null): void;
|
|
274
|
+
registerOnChange(fn: (data: OutputData) => void): void;
|
|
275
|
+
registerOnTouched(fn: () => void): void;
|
|
276
|
+
/** Form disabled state maps to the editor's read-only mode (via the readOnly effect). */
|
|
277
|
+
setDisabledState(isDisabled: boolean): void;
|
|
278
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<BlokEditorComponent, never>;
|
|
279
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<BlokEditorComponent, "blok-editor", ["blok"], {
|
|
280
|
+
"onBeforeRender": {
|
|
281
|
+
"alias": "onBeforeRender";
|
|
282
|
+
"required": false;
|
|
283
|
+
};
|
|
284
|
+
"onBeforePaste": {
|
|
285
|
+
"alias": "onBeforePaste";
|
|
286
|
+
"required": false;
|
|
287
|
+
};
|
|
288
|
+
"onError": {
|
|
289
|
+
"alias": "onError";
|
|
290
|
+
"required": false;
|
|
291
|
+
};
|
|
292
|
+
"onImageFailure": {
|
|
293
|
+
"alias": "onImageFailure";
|
|
294
|
+
"required": false;
|
|
295
|
+
};
|
|
296
|
+
"readOnly": {
|
|
297
|
+
"alias": "readOnly";
|
|
298
|
+
"required": false;
|
|
299
|
+
};
|
|
300
|
+
"hideToolbar": {
|
|
301
|
+
"alias": "hideToolbar";
|
|
302
|
+
"required": false;
|
|
303
|
+
};
|
|
304
|
+
"toolbarPosition": {
|
|
305
|
+
"alias": "toolbarPosition";
|
|
306
|
+
"required": false;
|
|
307
|
+
};
|
|
308
|
+
"inlineToolbar": {
|
|
309
|
+
"alias": "inlineToolbar";
|
|
310
|
+
"required": false;
|
|
311
|
+
};
|
|
312
|
+
"theme": {
|
|
313
|
+
"alias": "theme";
|
|
314
|
+
"required": false;
|
|
315
|
+
};
|
|
316
|
+
"width": {
|
|
317
|
+
"alias": "width";
|
|
318
|
+
"required": false;
|
|
319
|
+
};
|
|
320
|
+
"placeholder": {
|
|
321
|
+
"alias": "placeholder";
|
|
322
|
+
"required": false;
|
|
323
|
+
};
|
|
324
|
+
"styleTokens": {
|
|
325
|
+
"alias": "styleTokens";
|
|
326
|
+
"required": false;
|
|
327
|
+
};
|
|
328
|
+
"i18n": {
|
|
329
|
+
"alias": "i18n";
|
|
330
|
+
"required": false;
|
|
331
|
+
};
|
|
332
|
+
"autofocus": {
|
|
333
|
+
"alias": "autofocus";
|
|
334
|
+
"required": false;
|
|
335
|
+
};
|
|
336
|
+
"data": {
|
|
337
|
+
"alias": "data";
|
|
338
|
+
"required": false;
|
|
339
|
+
};
|
|
340
|
+
"tools": {
|
|
341
|
+
"alias": "tools";
|
|
342
|
+
"required": false;
|
|
343
|
+
};
|
|
344
|
+
"migrations": {
|
|
345
|
+
"alias": "migrations";
|
|
346
|
+
"required": false;
|
|
347
|
+
};
|
|
348
|
+
"config": {
|
|
349
|
+
"alias": "config";
|
|
350
|
+
"required": false;
|
|
351
|
+
};
|
|
352
|
+
"recreateKey": {
|
|
353
|
+
"alias": "recreateKey";
|
|
354
|
+
"required": false;
|
|
355
|
+
};
|
|
356
|
+
}, {
|
|
357
|
+
"ready": "ready";
|
|
358
|
+
"dataChange": "dataChange";
|
|
359
|
+
"save": "save";
|
|
360
|
+
"change": "change";
|
|
361
|
+
"afterRender": "afterRender";
|
|
362
|
+
"themeChange": "themeChange";
|
|
363
|
+
"blocksRendered": "blocksRendered";
|
|
364
|
+
"blockRendered": "blockRendered";
|
|
365
|
+
}, never, never, true, never>;
|
|
257
366
|
}
|
|
258
|
-
|
|
367
|
+
/**
|
|
368
|
+
* The `collaboration` the given editor was constructed with.
|
|
369
|
+
* @param editor - a Blok instance built by `BlokContentDirective`
|
|
370
|
+
* @returns the mount-time collaboration config, `undefined` when there was none
|
|
371
|
+
*/
|
|
372
|
+
declare function getConstructedCollaboration(editor: WeakKey): BlokAngularConfig['collaboration'];
|
|
259
373
|
/**
|
|
260
374
|
* Escape-hatch directive and lifecycle engine for Blok (mirrors React's
|
|
261
375
|
* `useBlok` + `BlokContent`). Constructs a Blok instance into its own host
|
|
@@ -274,47 +388,57 @@ declare class BlokEditorComponent implements AfterViewInit, DoCheck, ControlValu
|
|
|
274
388
|
* adapter via JIT, which does not register signal-based members. `instance`
|
|
275
389
|
* remains a plain `signal` (runtime API, JIT-safe) for reactive consumption.
|
|
276
390
|
*/
|
|
277
|
-
declare class BlokContentDirective implements OnDestroy {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
391
|
+
export declare class BlokContentDirective implements OnDestroy {
|
|
392
|
+
private readonly host;
|
|
393
|
+
private readonly ngZone;
|
|
394
|
+
private readonly isBrowser;
|
|
395
|
+
/**
|
|
396
|
+
* App-wide defaults from `provideBlok()`, merged UNDER the bound `[config]` so
|
|
397
|
+
* the escape-hatch path honors them just like `<blok-editor>` (which also
|
|
398
|
+
* merges, idempotently). Mirrors React's `useBlok` merging context defaults.
|
|
399
|
+
*/
|
|
400
|
+
private readonly defaults;
|
|
401
|
+
private readonly envInjector;
|
|
402
|
+
private readonly appRef;
|
|
403
|
+
private readonly errorHandler;
|
|
404
|
+
/** Construction-time Blok config (everything except `holder`, which the directive owns). */
|
|
405
|
+
config: Partial<BlokAngularConfig>;
|
|
406
|
+
/** Changing this input's identity (after the first build) destroys + recreates the editor. */
|
|
407
|
+
set recreateKey(value: unknown);
|
|
408
|
+
/** Emits the live Blok instance once it is ready, after `instance` is populated. */
|
|
409
|
+
readonly ready: EventEmitter<Blok>;
|
|
410
|
+
/** The live Blok instance, or null before `isReady` resolves / after destroy. */
|
|
411
|
+
readonly instance: import("@angular/core").WritableSignal<Blok | null>;
|
|
412
|
+
/** The editor created by the most recent construction; used as the staleness key. */
|
|
413
|
+
private current;
|
|
414
|
+
private destroyed;
|
|
415
|
+
private built;
|
|
416
|
+
private currentKey;
|
|
417
|
+
/** The portal registry for the current editor (Angular-block mounting). */
|
|
418
|
+
private registry;
|
|
419
|
+
constructor();
|
|
420
|
+
/** Construct a Blok into the host element and publish it once ready. */
|
|
421
|
+
private build;
|
|
422
|
+
ngOnDestroy(): void;
|
|
423
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<BlokContentDirective, never>;
|
|
424
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<BlokContentDirective, "[blokContent]", never, {
|
|
425
|
+
"config": {
|
|
426
|
+
"alias": "config";
|
|
427
|
+
"required": false;
|
|
428
|
+
};
|
|
429
|
+
"recreateKey": {
|
|
430
|
+
"alias": "recreateKey";
|
|
431
|
+
"required": false;
|
|
432
|
+
};
|
|
433
|
+
}, {
|
|
434
|
+
"ready": "ready";
|
|
435
|
+
}, never, never, true, never>;
|
|
311
436
|
}
|
|
312
|
-
|
|
313
437
|
/**
|
|
314
438
|
* DI token holding app-wide Blok defaults (shared tools registry, default theme,
|
|
315
439
|
* i18n). Merged under per-instance inputs by `BlokEditorComponent`.
|
|
316
440
|
*/
|
|
317
|
-
declare const BLOK_DEFAULT_CONFIG: InjectionToken<Partial<BlokAngularConfig>>;
|
|
441
|
+
export declare const BLOK_DEFAULT_CONFIG: InjectionToken<Partial<BlokAngularConfig>>;
|
|
318
442
|
/**
|
|
319
443
|
* Standalone provider registering app-wide Blok defaults.
|
|
320
444
|
*
|
|
@@ -325,16 +449,15 @@ declare const BLOK_DEFAULT_CONFIG: InjectionToken<Partial<BlokAngularConfig>>;
|
|
|
325
449
|
* });
|
|
326
450
|
* ```
|
|
327
451
|
*/
|
|
328
|
-
declare function provideBlok(defaults: Partial<BlokAngularConfig>): EnvironmentProviders;
|
|
329
|
-
|
|
452
|
+
export declare function provideBlok(defaults: Partial<BlokAngularConfig>): EnvironmentProviders;
|
|
330
453
|
/**
|
|
331
454
|
* Where to place the caret within a block. `position` selects the input
|
|
332
455
|
* (`'start'`/`'end'`/`'default'`) and `offset` is the character offset within it
|
|
333
456
|
* — the same shape core's `caret.setToBlock` accepts.
|
|
334
457
|
*/
|
|
335
458
|
interface CaretTarget {
|
|
336
|
-
|
|
337
|
-
|
|
459
|
+
position?: 'start' | 'end' | 'default';
|
|
460
|
+
offset?: number;
|
|
338
461
|
}
|
|
339
462
|
/**
|
|
340
463
|
* A plain, serializable view of one block in the tree.
|
|
@@ -346,52 +469,48 @@ interface CaretTarget {
|
|
|
346
469
|
* identity; depend on the `id` instead.
|
|
347
470
|
*/
|
|
348
471
|
interface BlockNode {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
472
|
+
id: string;
|
|
473
|
+
type: string;
|
|
474
|
+
parentId: string | null;
|
|
475
|
+
contentIds: readonly string[];
|
|
353
476
|
}
|
|
354
477
|
/** Where to place a block among its siblings. */
|
|
355
|
-
type InsertPosition =
|
|
356
|
-
before: string;
|
|
357
|
-
} | {
|
|
358
|
-
after: string;
|
|
359
|
-
};
|
|
478
|
+
type InsertPosition = BlockPosition;
|
|
360
479
|
interface InsertSpec {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
480
|
+
type?: string;
|
|
481
|
+
data?: BlockToolData;
|
|
482
|
+
parentId?: string | null;
|
|
483
|
+
position?: InsertPosition;
|
|
484
|
+
/**
|
|
485
|
+
* Move the caret into the new block. Defaults to `false`: a programmatic
|
|
486
|
+
* insert from React must not steal focus from wherever the user is typing.
|
|
487
|
+
* Set `true` for an explicit "add a block and start editing it" flow.
|
|
488
|
+
*/
|
|
489
|
+
focus?: boolean;
|
|
490
|
+
/**
|
|
491
|
+
* Replace the block at the resolved slot instead of inserting a new one — a
|
|
492
|
+
* programmatic "turn into". Combine with a `position` that targets the block
|
|
493
|
+
* to replace, e.g. `{ position: { before: id }, replace: true }`.
|
|
494
|
+
*/
|
|
495
|
+
replace?: boolean;
|
|
496
|
+
/**
|
|
497
|
+
* Explicit id for the new block (generated when omitted). Passing a stable id
|
|
498
|
+
* makes the insert idempotent: if a block with this id already exists the
|
|
499
|
+
* existing node is returned and nothing is inserted ("insert if absent"),
|
|
500
|
+
* so an effect that re-runs won't create duplicates.
|
|
501
|
+
*/
|
|
502
|
+
id?: string;
|
|
503
|
+
/** Block tune data to apply at creation, keyed by tune name. */
|
|
504
|
+
tunes?: {
|
|
505
|
+
[name: string]: BlockTuneData;
|
|
506
|
+
};
|
|
507
|
+
/**
|
|
508
|
+
* Place the caret inside the newly-created block at a specific position/offset
|
|
509
|
+
* (e.g. `{ offset: 3 }`). Implies focus. Applied ONLY when a block is actually
|
|
510
|
+
* created — an insert-if-absent hit (existing id) does not move the caret.
|
|
511
|
+
* Use this instead of the boolean `focus` when you need a specific offset.
|
|
512
|
+
*/
|
|
513
|
+
caret?: CaretTarget;
|
|
395
514
|
}
|
|
396
515
|
/**
|
|
397
516
|
* One node of a pre-built nested subtree for {@link UseBlocksApi.insertTree}.
|
|
@@ -403,270 +522,517 @@ interface InsertSpec {
|
|
|
403
522
|
* is always their enclosing node.
|
|
404
523
|
*/
|
|
405
524
|
interface TreeInsertSpec {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
525
|
+
type?: string;
|
|
526
|
+
data?: BlockToolData;
|
|
527
|
+
tunes?: {
|
|
528
|
+
[name: string]: BlockTuneData;
|
|
529
|
+
};
|
|
530
|
+
/**
|
|
531
|
+
* Explicit id for this node (generated when omitted). Unlike `insert`, this is
|
|
532
|
+
* NOT insert-if-absent: a tree insert always creates fresh blocks. A colliding
|
|
533
|
+
* id — one that already exists in the document, or is reused by another node
|
|
534
|
+
* in the same spec — is REJECTED up front: nothing is inserted and `insertTree`
|
|
535
|
+
* returns `null` (a duplicate id would corrupt every id-keyed lookup).
|
|
536
|
+
*/
|
|
537
|
+
id?: string;
|
|
538
|
+
/** Direct children, inserted nested under this node, in array order. */
|
|
539
|
+
children?: TreeInsertSpec[];
|
|
540
|
+
/** Root-only: where to place the whole subtree. Ignored on nested children. */
|
|
541
|
+
parentId?: string | null;
|
|
542
|
+
/** Root-only: slot among siblings of `parentId`. Ignored on nested children. */
|
|
543
|
+
position?: InsertPosition;
|
|
425
544
|
}
|
|
426
545
|
/**
|
|
427
546
|
* Where to move an existing block.
|
|
428
547
|
*
|
|
429
|
-
* `before`/`after`
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
* `nest`/`unnest` when you want to change the parent without choosing a sibling
|
|
435
|
-
* slot. `toIndex` is an absolute flat index (clamped into range).
|
|
548
|
+
* `before`/`after` make the block a sibling of the ref: it takes the ref's
|
|
549
|
+
* parent. Moving a nested block to `{ after: someRootBlock }` therefore unnests
|
|
550
|
+
* it to root, and moving a root block next to a container's child nests it.
|
|
551
|
+
* Use `nest`/`unnest` when you want to change the parent without choosing a
|
|
552
|
+
* sibling slot. `toIndex` is an absolute flat index (clamped into range).
|
|
436
553
|
*/
|
|
437
554
|
type MoveTarget = {
|
|
438
|
-
|
|
555
|
+
before: string;
|
|
439
556
|
} | {
|
|
440
|
-
|
|
557
|
+
after: string;
|
|
441
558
|
} | {
|
|
442
|
-
|
|
559
|
+
toIndex: number;
|
|
443
560
|
};
|
|
444
561
|
interface UseBlocksApi {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
562
|
+
getById(id: string): BlockNode | null;
|
|
563
|
+
getChildren(parentId: string | null): BlockNode[];
|
|
564
|
+
/**
|
|
565
|
+
* Insert one block; returns the created node or null when rejected (unknown
|
|
566
|
+
* tool type, dangling `parentId`, or a `replace` whose target is missing). An
|
|
567
|
+
* explicit `id` that already exists is insert-if-absent (returns the existing
|
|
568
|
+
* node, creates nothing). Atomic — one undo step. The returned node is
|
|
569
|
+
* {@link BlockNode}-volatile; read it now, don't put it in a dep array.
|
|
570
|
+
*/
|
|
571
|
+
insert(spec?: InsertSpec): BlockNode | null;
|
|
572
|
+
/**
|
|
573
|
+
* Insert several blocks atomically, in array order, as ONE undo step. Each
|
|
574
|
+
* spec is a full {@link InsertSpec} (own type/data/parentId/position), routed
|
|
575
|
+
* through the same single-`insert` path, so per-spec parent assertion and
|
|
576
|
+
* positioning still apply. Specs that fail to insert (e.g. a dangling
|
|
577
|
+
* parentId, or a replace whose target is missing) are dropped; the returned
|
|
578
|
+
* array holds only the successfully created nodes. An empty input is a no-op
|
|
579
|
+
* (returns `[]`, opens no transaction). Like `insert`, the returned nodes are
|
|
580
|
+
* fresh-snapshot volatile — read them now, don't stash them in dep arrays.
|
|
581
|
+
*/
|
|
582
|
+
insertMany(specs: InsertSpec[]): BlockNode[];
|
|
583
|
+
/**
|
|
584
|
+
* Insert a pre-built NESTED subtree in ONE atomic operation (one undo step).
|
|
585
|
+
* Each {@link TreeInsertSpec} node becomes a block; its `children` are inserted
|
|
586
|
+
* nested under it (recursively, in array order) so the whole hierarchy lands in
|
|
587
|
+
* a single call — no follow-up `nest` round-trips. Delegates to core's
|
|
588
|
+
* tree-aware `blocks.insertMany`, which composes the flat DFS pre-order array
|
|
589
|
+
* honoring each node's `parent`/`content` links.
|
|
590
|
+
*
|
|
591
|
+
* Placement is root-only: the root node's `parentId`/`position` position the
|
|
592
|
+
* whole subtree among existing blocks (default: appended at the document end);
|
|
593
|
+
* nested children ignore those fields (their parent is their enclosing node). A
|
|
594
|
+
* dangling root `parentId` is rejected — nothing is inserted and `null` is
|
|
595
|
+
* returned (mirrors {@link insert}). Returns the root {@link BlockNode}, which
|
|
596
|
+
* is fresh-snapshot volatile — read it now, don't stash it in a dep array.
|
|
597
|
+
*/
|
|
598
|
+
insertTree(spec: TreeInsertSpec): BlockNode | null;
|
|
599
|
+
/**
|
|
600
|
+
* Convert a Markdown string to blocks and insert them ADDITIVELY at a
|
|
601
|
+
* position, WITHOUT clearing the document (unlike core's `importMarkdown` /
|
|
602
|
+
* `renderFromHTML`, which replace the whole document). This is the React
|
|
603
|
+
* "paste markdown → blocks appear" path.
|
|
604
|
+
*
|
|
605
|
+
* Async: the markdown converter is lazy-loaded (kept out of the main bundle),
|
|
606
|
+
* so this is the ONE async creator in the API — `await` the returned promise.
|
|
607
|
+
* The whole batch is inserted as a single atomic undo step.
|
|
608
|
+
*
|
|
609
|
+
* `position` (default `'end'`) places the converted run among `parentId`'s
|
|
610
|
+
* children (or root siblings when `parentId` is omitted/null), reusing the
|
|
611
|
+
* same `start`/`end`/`before`/`after` semantics as {@link insert}.
|
|
612
|
+
*
|
|
613
|
+
* `parentId` (default `null` = root) nests the import: every TOP-LEVEL
|
|
614
|
+
* converted block (one the converter left un-parented) is reparented under
|
|
615
|
+
* `parentId`, while blocks the markdown nested internally (e.g. table-cell
|
|
616
|
+
* children) keep their intra-import parent. A dangling `parentId` is a no-op
|
|
617
|
+
* (returns `[]`, opens no transaction), matching {@link insert}.
|
|
618
|
+
*
|
|
619
|
+
* `config` (optional {@link MarkdownImportConfig}) is forwarded to the
|
|
620
|
+
* converter so custom-tool consumers can map markdown nodes into their tools
|
|
621
|
+
* (`toolMap`/`onUnknownNode`), toggle GFM, or add micromark/mdast extensions.
|
|
622
|
+
*
|
|
623
|
+
* Returns ALL created {@link BlockNode}s in document order — including any the
|
|
624
|
+
* markdown nested internally (e.g. a table's cell children), not just the
|
|
625
|
+
* top-level run (this differs from {@link insertTree}, which returns only the
|
|
626
|
+
* root). Empty or whitespace-only markdown, a dangling `parentId` (checked
|
|
627
|
+
* again after the async convert, so a parent removed mid-flight also no-ops),
|
|
628
|
+
* and a converter failure (chunk-load or parse error, swallowed) all return
|
|
629
|
+
* `[]` and open no transaction. The nodes are fresh-snapshot volatile — read
|
|
630
|
+
* them now, don't stash them in dep arrays.
|
|
631
|
+
*/
|
|
632
|
+
insertMarkdown(markdown: string, options?: {
|
|
633
|
+
parentId?: string | null;
|
|
634
|
+
position?: InsertPosition;
|
|
635
|
+
config?: MarkdownImportConfig;
|
|
636
|
+
}): Promise<BlockNode[]>;
|
|
637
|
+
/**
|
|
638
|
+
* Serialize the WHOLE document to a Markdown string — the outbound twin of
|
|
639
|
+
* core's `blocks.exportMarkdown` (and the read-side counterpart of the
|
|
640
|
+
* additive {@link insertMarkdown}). Async: the serializer is lazy-loaded, like
|
|
641
|
+
* the importer. Markdown cannot express every block, so some structure is
|
|
642
|
+
* dropped (table `colspan`/`rowspan`, heading columns). Returns `''` for an
|
|
643
|
+
* empty document. Pre-ready: resolves to `''`.
|
|
644
|
+
*/
|
|
645
|
+
exportMarkdown(): Promise<string>;
|
|
646
|
+
move(id: string, target: MoveTarget): void;
|
|
647
|
+
nest(id: string, parentId: string): void;
|
|
648
|
+
unnest(id: string): void;
|
|
649
|
+
remove(id: string): void;
|
|
650
|
+
/**
|
|
651
|
+
* Update a block's data and/or tunes by id. Delegates to core's async
|
|
652
|
+
* `blocks.update`, which forms its OWN undo step — the call is NOT wrapped in
|
|
653
|
+
* `transact` (that would close the group before the async write lands). An
|
|
654
|
+
* unknown id is a silent no-op; a rejected update is swallowed so it can't
|
|
655
|
+
* surface as an unhandled rejection. Reads refresh reactively once core emits
|
|
656
|
+
* 'block changed'. Returns `void`.
|
|
657
|
+
*/
|
|
658
|
+
update(id: string, data?: BlockToolData, tunes?: {
|
|
659
|
+
[name: string]: BlockTuneData;
|
|
660
|
+
}): void;
|
|
661
|
+
/**
|
|
662
|
+
* Convert a block to another type ("turn into") by id. Delegates to core's
|
|
663
|
+
* async `blocks.convert`; both tools must provide a `conversionConfig` or core
|
|
664
|
+
* rejects — that rejection (and any other) is swallowed so a non-convertible
|
|
665
|
+
* block is a graceful no-op rather than an unhandled rejection. An unknown id
|
|
666
|
+
* is a silent no-op. Not wrapped in `transact` (core owns its history step).
|
|
667
|
+
* Returns `void`.
|
|
668
|
+
*/
|
|
669
|
+
convert(id: string, newType: string, dataOverrides?: BlockToolData, options?: {
|
|
670
|
+
caret?: CaretTarget;
|
|
671
|
+
}): void;
|
|
672
|
+
transact(fn: () => void): void;
|
|
673
|
+
/**
|
|
674
|
+
* Run `fn` as one atomic operation that is NOT captured in the undo history —
|
|
675
|
+
* the React-surface counterpart of core's `transactWithoutCapture`. Use for
|
|
676
|
+
* silent auto-repair/normalization that a user's CMD+Z should never step
|
|
677
|
+
* through. Mutations inside still emit reactively. Pre-ready it just runs `fn`.
|
|
678
|
+
*
|
|
679
|
+
* With `options`, the operations are data worked out from the `from` keys of
|
|
680
|
+
* block `derivedFrom` (a finished upload, for example): they join the undo
|
|
681
|
+
* entry that wrote those values, as in core.
|
|
682
|
+
*/
|
|
683
|
+
transactWithoutCapture(fn: () => void, options?: {
|
|
684
|
+
derivedFrom?: string;
|
|
685
|
+
from?: readonly string[];
|
|
686
|
+
}): void;
|
|
687
|
+
/**
|
|
688
|
+
* The current block count. Reactive (re-reads on 'block changed'). Pre-ready: 0.
|
|
689
|
+
*/
|
|
690
|
+
getBlocksCount(): number;
|
|
691
|
+
/**
|
|
692
|
+
* The flat index of the block holding the caret, or -1 when none. Pre-ready: -1.
|
|
693
|
+
*/
|
|
694
|
+
getCurrentBlockIndex(): number;
|
|
695
|
+
/** The block at a flat index as a snapshot {@link BlockNode}, or null. */
|
|
696
|
+
getBlockByIndex(index: number): BlockNode | null;
|
|
697
|
+
/**
|
|
698
|
+
* The absolute flat index of a block by id, or null when unknown. The
|
|
699
|
+
* counterpart to {@link getBlockByIndex} — use it to target an off-caret
|
|
700
|
+
* {@link splitBlock} (whose `insertIndex` is absolute) without the ref. Unknown
|
|
701
|
+
* ids return null silently (no console warn). Pre-ready: null.
|
|
702
|
+
*/
|
|
703
|
+
getBlockIndex(id: string): number | null;
|
|
704
|
+
/**
|
|
705
|
+
* Read a block's current `data` and `tunes` by id WITHOUT mutating anything —
|
|
706
|
+
* the synchronous last-extracted view (the same snapshot clipboard ops use).
|
|
707
|
+
* Makes a client-side duplicate composable from the hook alone: read a node,
|
|
708
|
+
* then `insert({ type, data, tunes, position })`, no ref escape hatch. Unknown
|
|
709
|
+
* id returns null. Pre-ready: null.
|
|
710
|
+
*/
|
|
711
|
+
getBlockData(id: string): {
|
|
712
|
+
data: BlockToolData;
|
|
713
|
+
tunes: {
|
|
714
|
+
[name: string]: BlockTuneData;
|
|
715
|
+
};
|
|
716
|
+
} | null;
|
|
717
|
+
/**
|
|
718
|
+
* The block whose holder contains/equals `element`, as a snapshot
|
|
719
|
+
* {@link BlockNode}, or null. Useful for mapping a DOM event target back to a
|
|
720
|
+
* block.
|
|
721
|
+
*/
|
|
722
|
+
getBlockByElement(element: HTMLElement): BlockNode | null;
|
|
723
|
+
/**
|
|
724
|
+
* Read a tool's default empty data WITHOUT inserting anything — delegates to
|
|
725
|
+
* core's `composeBlockData`. Async (a tool's data may be composed lazily).
|
|
726
|
+
* Rejects (via core) for an unknown tool. Pre-ready: resolves to `{}`.
|
|
727
|
+
*/
|
|
728
|
+
composeBlockData(toolName: string): Promise<BlockToolData>;
|
|
729
|
+
/**
|
|
730
|
+
* Replace the WHOLE document with blocks parsed from an HTML string —
|
|
731
|
+
* delegates to core's `renderFromHTML`. Unlike {@link insertMarkdown} (which is
|
|
732
|
+
* additive), this CLEARS existing content first, so it's a document-load
|
|
733
|
+
* primitive, not an insert. Async. Pre-ready: resolves immediately (no-op).
|
|
734
|
+
*/
|
|
735
|
+
renderFromHTML(html: string): Promise<void>;
|
|
736
|
+
/**
|
|
737
|
+
* Insert a flat array of already-serialized {@link OutputBlockData} (the
|
|
738
|
+
* `save()` shape) directly, honoring each block's `parent`/`content` links —
|
|
739
|
+
* the raw counterpart of core's `blocks.insertMany`. Use to re-insert a saved
|
|
740
|
+
* document fragment without reshaping it into {@link TreeInsertSpec}. One
|
|
741
|
+
* atomic undo step. Returns the created nodes; pre-ready: `[]` (no insert).
|
|
742
|
+
*/
|
|
743
|
+
insertOutputData(blocks: OutputBlockData[], options?: {
|
|
744
|
+
index?: number;
|
|
745
|
+
}): BlockNode[];
|
|
746
|
+
/**
|
|
747
|
+
* Atomically split a block: update `currentBlockId` with `currentBlockData`
|
|
748
|
+
* and insert a new `newBlockType` block at `insertIndex`, as ONE undo step.
|
|
749
|
+
* Delegates to core's `splitBlock`. Returns the new node, or null pre-ready /
|
|
750
|
+
* on an unknown id.
|
|
751
|
+
*/
|
|
752
|
+
splitBlock(currentBlockId: string, currentBlockData: Partial<BlockToolData>, newBlockType: string, newBlockData: BlockToolData, insertIndex: number): BlockNode | null;
|
|
753
|
+
/**
|
|
754
|
+
* Insert a single child block under `parentId` at flat `insertIndex`, atomically
|
|
755
|
+
* (block creation AND parent assignment in ONE undo step) — delegates to core's
|
|
756
|
+
* `blocks.insertInsideParent`. This is the atomic nested-child creator: prefer it
|
|
757
|
+
* over `insert()` + `nest()`, which is TWO undo steps. A dangling `parentId` is a
|
|
758
|
+
* no-op returning `null` (mirrors {@link insert}); an unknown child tool returns
|
|
759
|
+
* `null`. `childData` defaults to an empty paragraph. Returns the created
|
|
760
|
+
* {@link BlockNode}, fresh-snapshot volatile — read it now, don't stash it in a
|
|
761
|
+
* dep array. Pre-ready: `null`.
|
|
762
|
+
*/
|
|
763
|
+
insertInsideParent(parentId: string, insertIndex: number, childData?: BlockToolData): BlockNode | null;
|
|
764
|
+
/**
|
|
765
|
+
* Replace the WHOLE document with blocks parsed from saved {@link OutputData}
|
|
766
|
+
* (the `save()` shape) — delegates to core's `blocks.render`. Unlike
|
|
767
|
+
* {@link insertOutputData}/{@link insertMarkdown} (which are ADDITIVE), this
|
|
768
|
+
* CLEARS existing content first: a document-LOAD primitive, not an insert. The
|
|
769
|
+
* HTML counterpart is {@link renderFromHTML}. Async. Pre-ready: resolves
|
|
770
|
+
* immediately (no-op).
|
|
771
|
+
*/
|
|
772
|
+
render(data: OutputData): Promise<void>;
|
|
773
|
+
/**
|
|
774
|
+
* Remove EVERY block from the document — delegates to core's `blocks.clear`. A
|
|
775
|
+
* document-reset primitive (pairs with {@link render}). Async. Pre-ready:
|
|
776
|
+
* resolves immediately (no-op).
|
|
777
|
+
*/
|
|
778
|
+
clear(): Promise<void>;
|
|
779
|
+
/**
|
|
780
|
+
* Whether a Yjs sync (undo/redo) is currently in progress — the React mirror of
|
|
781
|
+
* core's `blocks.isSyncingFromYjs`. A METHOD (not a property) so it reads the
|
|
782
|
+
* LIVE flag at call time even though the api handle is memoized. Use it to skip
|
|
783
|
+
* cleanup that would fight Yjs state during an undo/redo. Pre-ready: `false`.
|
|
784
|
+
*/
|
|
785
|
+
isSyncingFromYjs(): boolean;
|
|
786
|
+
}
|
|
787
|
+
/** The minimal slice of editor.blocks that the snapshot helpers read. */
|
|
788
|
+
interface BlocksReader {
|
|
789
|
+
getBlocksCount(): number;
|
|
790
|
+
getBlockByIndex(index: number): {
|
|
791
|
+
id: string;
|
|
792
|
+
name: string;
|
|
793
|
+
parentId: string | null;
|
|
794
|
+
} | undefined;
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Enumerate the editor's blocks once into BlockNode records, in flat order,
|
|
798
|
+
* deriving each node's contentIds from the children that name it as parent.
|
|
799
|
+
*/
|
|
800
|
+
declare const snapshotNodes: (reader: BlocksReader) => BlockNode[];
|
|
801
|
+
/** BlocksReader plus id→flat-index lookup. */
|
|
802
|
+
interface IndexReader extends BlocksReader {
|
|
803
|
+
getBlockIndex(id: string): number | undefined;
|
|
804
|
+
}
|
|
805
|
+
/** Map of block id -> parentId, in flat order. */
|
|
806
|
+
declare const parentMap: (reader: BlocksReader) => Map<string, string | null>;
|
|
807
|
+
/** True if `id` descends from `ancestorId` via the parentId chain. */
|
|
808
|
+
declare const isDescendantOf: (parentOf: Map<string, string | null>, id: string, ancestorId: string) => boolean;
|
|
809
|
+
/**
|
|
810
|
+
* The flat index of the last block in the contiguous subtree rooted at `index`.
|
|
811
|
+
* In flat (DFS) order a block's descendants sit immediately after it, so this
|
|
812
|
+
* walks forward while blocks remain descendants of the block at `index`.
|
|
813
|
+
* Returns `index` itself when the block has no descendants.
|
|
814
|
+
*/
|
|
815
|
+
declare const subtreeEndIndex: (reader: BlocksReader, index: number) => number;
|
|
816
|
+
/**
|
|
817
|
+
* The flat index at which a new block should be inserted.
|
|
818
|
+
*
|
|
819
|
+
* `replace` flips the meaning of a before/after `position`: under replace the
|
|
820
|
+
* ref IS the block being overwritten (a "turn into"), not a sibling anchor, so
|
|
821
|
+
* it resolves to the ref's OWN flat slot regardless of which parent it lives in
|
|
822
|
+
* — bypassing the sibling-relative parent guard that would otherwise redirect a
|
|
823
|
+
* nested target to the requested parent's end and replace the wrong block.
|
|
824
|
+
*/
|
|
825
|
+
declare const resolveInsertIndex: (reader: IndexReader, parentId: string | null, position: InsertPosition, replace?: boolean) => number;
|
|
826
|
+
/** The flat toIndex for editor.blocks.move. */
|
|
827
|
+
declare const resolveMoveIndex: (reader: IndexReader, target: MoveTarget) => number;
|
|
828
|
+
/** Adapt the live editor to the IndexReader the snapshot helpers expect. */
|
|
829
|
+
declare const readerFor: (editor: Blok) => IndexReader;
|
|
830
|
+
/**
|
|
831
|
+
* Stable API returned while the editor is null (before the adapter resolves).
|
|
832
|
+
* Every read returns empty/null and every MUTATOR is a no-op — EXCEPT
|
|
833
|
+
* `transact`/`transactWithoutCapture`, which still invoke their callback so a
|
|
834
|
+
* consumer wrapping conditional work in `transact` still runs that work even
|
|
835
|
+
* pre-ready.
|
|
836
|
+
*/
|
|
837
|
+
declare const EMPTY_API: UseBlocksApi;
|
|
838
|
+
/**
|
|
839
|
+
* Does a `block changed` event touch the subtree rooted at `withinId`?
|
|
840
|
+
*
|
|
841
|
+
* The reactivity filter behind `useBlocks(editor, { within })` in all three
|
|
842
|
+
* adapters. Without it every consumer of `useBlocks` re-renders on every change
|
|
843
|
+
* anywhere in the document — so a container block that only renders its own
|
|
844
|
+
* children still re-rendered on each keystroke in an unrelated block, and a page
|
|
845
|
+
* of N such containers turned one keystroke into N re-renders.
|
|
846
|
+
*
|
|
847
|
+
* INDETERMINATE READS AS "TOUCHED". The walk resolves ancestry through the LIVE
|
|
848
|
+
* tree, and a removal commonly emits after the block is already gone, so its
|
|
849
|
+
* parent chain cannot be read. Answering `false` there would leave a container
|
|
850
|
+
* rendering a child that no longer exists; answering `true` costs one extra
|
|
851
|
+
* render pass. Same for a payload with no readable target.
|
|
852
|
+
*
|
|
853
|
+
* Ancestry is walked UPWARD one `getById` at a time rather than snapshotted with
|
|
854
|
+
* `parentMap`: this runs on every emission — i.e. on every keystroke — so it must
|
|
855
|
+
* cost O(depth), not O(document).
|
|
856
|
+
* @param editor - the live Blok instance
|
|
857
|
+
* @param payload - the `block changed` payload
|
|
858
|
+
* @param withinId - id of the block whose subtree is the scope
|
|
859
|
+
* @returns true when the change is inside the scope (or cannot be placed)
|
|
860
|
+
*/
|
|
861
|
+
declare const changeTouchesSubtree: (editor: Blok, payload: unknown, withinId: string) => boolean;
|
|
862
|
+
/**
|
|
863
|
+
* Build the framework-agnostic, id/parentId-relative block-tree API over a LIVE
|
|
864
|
+
* editor. Mutators route through the editor-level `blocks` API (core's
|
|
865
|
+
* chokepoints), so undo/redo and Yjs sync are inherited rather than
|
|
866
|
+
* re-implemented; readers enumerate the live tree on every call.
|
|
867
|
+
*
|
|
868
|
+
* This is the shared engine behind both the React (`useSyncExternalStore`) and
|
|
869
|
+
* Vue (`shallowRef` version) `useBlocks` wrappers — one implementation so the
|
|
870
|
+
* two adapters cannot drift. Each adapter supplies the `onRead` seam:
|
|
871
|
+
*
|
|
872
|
+
* - React leaves it the default no-op: `useSyncExternalStore` re-renders the
|
|
873
|
+
* whole component on `block changed`, and the reads run live during that
|
|
874
|
+
* render, so no per-call dependency tracking is needed.
|
|
875
|
+
* - Vue passes `() => { void version.value }` so a read inside a `computed` /
|
|
876
|
+
* template touches the reactive version ref and re-runs on every structural
|
|
877
|
+
* mutation.
|
|
878
|
+
*
|
|
879
|
+
* `onRead` is invoked at the top of every read method; mutators never call it.
|
|
880
|
+
* The editor MUST be the raw (non-proxied) instance — adapters `toRaw`-unwrap
|
|
881
|
+
* before calling, so a Vue reactive proxy never reaches core (Risk R0).
|
|
882
|
+
*
|
|
883
|
+
* @param editor - the live Blok instance (never null; callers gate on EMPTY_API)
|
|
884
|
+
* @param onRead - reactivity seam called at the start of each read (default no-op)
|
|
885
|
+
*/
|
|
886
|
+
declare const createBlocksApiForEditor: (editor: Blok, onRead?: () => void) => UseBlocksApi;
|
|
887
|
+
/**
|
|
888
|
+
* Normalized shape of the `readOnly` config option
|
|
889
|
+
*/
|
|
890
|
+
interface NormalizedReadOnlyConfig {
|
|
891
|
+
enabled: boolean;
|
|
892
|
+
hideControls: boolean;
|
|
662
893
|
}
|
|
663
|
-
|
|
894
|
+
/**
|
|
895
|
+
* Single source of truth for interpreting the `readOnly` config option.
|
|
896
|
+
* The object form always means read-only is enabled.
|
|
897
|
+
* @param value - raw `readOnly` value from BlokConfig
|
|
898
|
+
*/
|
|
899
|
+
declare function normalizeReadOnlyConfig(value: boolean | ReadOnlyModeConfig | undefined): NormalizedReadOnlyConfig;
|
|
900
|
+
/**
|
|
901
|
+
* Structural deep equality for JSON-like values (Blok `OutputData`).
|
|
902
|
+
*
|
|
903
|
+
* Framework-agnostic: shared by the React and Angular adapters to dedupe
|
|
904
|
+
* reactive `data` updates so identical content does not trigger a redundant
|
|
905
|
+
* re-render that would clobber the caret/selection. Handles the value shapes
|
|
906
|
+
* that appear in editor data: plain objects, arrays, and primitives (including
|
|
907
|
+
* `null`/`undefined`).
|
|
908
|
+
* @param a - first value to compare
|
|
909
|
+
* @param b - second value to compare
|
|
910
|
+
* @returns true when both values are structurally equal
|
|
911
|
+
*/
|
|
912
|
+
declare function deepEqual(a: unknown, b: unknown): boolean;
|
|
913
|
+
type AnyOutputData = OutputData | LooseOutputData | null | undefined;
|
|
914
|
+
/**
|
|
915
|
+
* Options for {@link equalsOutputData}.
|
|
916
|
+
*/
|
|
917
|
+
interface EqualsOutputDataOptions {
|
|
918
|
+
/**
|
|
919
|
+
* Ignore empty default blocks on both sides before comparing. A fresh editor
|
|
920
|
+
* always seeds one empty default paragraph, so a pristine document
|
|
921
|
+
* (`[{ type: 'paragraph', data: { text: '' } }]`) does not content-equal a
|
|
922
|
+
* saved-empty baseline (`[]`) by default. Turn this on for dirty-vs-baseline
|
|
923
|
+
* checks ("has the user actually typed anything?"): empty blocks of the
|
|
924
|
+
* default paragraph tool are dropped from both documents first, so pristine
|
|
925
|
+
* scaffolding and trailing empty lines don't register as a change. Empty
|
|
926
|
+
* NON-default blocks (a content-less divider, an empty image) are kept — they
|
|
927
|
+
* are meaningful content.
|
|
928
|
+
*/
|
|
929
|
+
ignoreEmptyDefaultBlocks?: boolean;
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* Structural equality for saved documents. Compares the `blocks` arrays
|
|
933
|
+
* deeply; the volatile `time` and `version` envelope fields are ignored, so a
|
|
934
|
+
* document round-tripped through `save()` compares equal to its echo. Block
|
|
935
|
+
* ids are compared only when both sides carry one — the editor mints fresh
|
|
936
|
+
* ids for id-less content, so a legacy document still equals its saved echo.
|
|
937
|
+
* Edit metadata (`lastEditedAt`/`lastEditedBy`) is ignored for the same reason:
|
|
938
|
+
* it records who touched a block and when, not what it says. Nullish documents
|
|
939
|
+
* compare equal to `{ blocks: [] }`.
|
|
940
|
+
*
|
|
941
|
+
* Pass `{ ignoreEmptyDefaultBlocks: true }` for dirty-vs-baseline checks so a
|
|
942
|
+
* pristine editor (one empty default paragraph) equals a saved-empty baseline —
|
|
943
|
+
* see {@link EqualsOutputDataOptions}.
|
|
944
|
+
* @param a - first document to compare
|
|
945
|
+
* @param b - second document to compare
|
|
946
|
+
* @param options - comparison options
|
|
947
|
+
* @returns true when both documents hold structurally equal blocks
|
|
948
|
+
*/
|
|
949
|
+
declare function equalsOutputData(a: AnyOutputData, b: AnyOutputData, options?: EqualsOutputDataOptions): boolean;
|
|
950
|
+
/**
|
|
951
|
+
* A bounded window of the editor's recently emitted `onSave` payloads, used by
|
|
952
|
+
* the framework adapters to recognize controlled-`data` echoes. Deduping
|
|
953
|
+
* against only the LAST emitted payload is not enough: a host that persists on
|
|
954
|
+
* save and refetches can hand the adapter a STALE echo — an earlier save
|
|
955
|
+
* arriving after a newer one already replaced the baseline — and re-rendering
|
|
956
|
+
* it would clobber the caret and any content typed since. Matching is
|
|
957
|
+
* structural ({@link equalsOutputData}), so envelopes reshaped in transit
|
|
958
|
+
* (fresh `time`, stripped ids) still count as echoes.
|
|
959
|
+
* @param capacity - number of payloads retained before the oldest is evicted
|
|
960
|
+
* @returns the echo window
|
|
961
|
+
*/
|
|
962
|
+
declare function createEmittedEchoWindow(capacity?: number): {
|
|
963
|
+
/** Records a payload the editor emitted via `onSave`. */
|
|
964
|
+
record(data: OutputData | LooseOutputData): void;
|
|
965
|
+
/** True when the document content-equals any recorded payload. */
|
|
966
|
+
matches(data: AnyOutputData): boolean;
|
|
967
|
+
/** Forgets all recorded payloads (external content took over). */
|
|
968
|
+
clear(): void;
|
|
969
|
+
};
|
|
970
|
+
/**
|
|
971
|
+
* A shared, deeply frozen empty document. Consumers persisting editor content
|
|
972
|
+
* repeatedly hand-write `{ blocks: [] }` for cleared/pristine baselines; this
|
|
973
|
+
* is the canonical value to use instead. Frozen (blocks array included) so a
|
|
974
|
+
* shared reference can never be mutated into a stale non-empty baseline.
|
|
975
|
+
*/
|
|
976
|
+
declare const EMPTY_OUTPUT_DATA: OutputData;
|
|
977
|
+
/**
|
|
978
|
+
* Maps a controlled `data` value to something the editor's `render()` accepts.
|
|
979
|
+
* A whole-document `null` — a controlled "clear to empty" — becomes
|
|
980
|
+
* `{ blocks: [] }`; any real document passes through untouched.
|
|
981
|
+
*
|
|
982
|
+
* The framework adapters (React/Vue/Angular) route their reactive `data` path
|
|
983
|
+
* through this so a `null` never reaches `render()`, whose strict guard reads
|
|
984
|
+
* `data.blocks` and would throw on `null`. `undefined` (uncontrolled) is handled
|
|
985
|
+
* by the adapters before this point, so it is intentionally not an input here.
|
|
986
|
+
* @param data - a controlled document, or `null` for an empty document
|
|
987
|
+
* @returns a document `render()` can consume
|
|
988
|
+
*/
|
|
989
|
+
declare function toRenderableData(data: OutputData | LooseOutputData | null): OutputData | LooseOutputData;
|
|
990
|
+
/**
|
|
991
|
+
* Normalizes blocks from the loose wire shape into the strict saved shape at
|
|
992
|
+
* the editor's input boundaries: a `null`/missing `data` becomes `{}`, a
|
|
993
|
+
* `null`/empty `id` is dropped so the block factory generates a fresh one, and
|
|
994
|
+
* nullish/empty hierarchy references (`parent`, `content`) are dropped so a
|
|
995
|
+
* root-level, childless block is spelled the one way the editor and `save()`
|
|
996
|
+
* both spell it — absent. Idempotent — strict blocks pass through unchanged
|
|
997
|
+
* (shallow-copied).
|
|
998
|
+
* @param blocks - blocks in either the strict or the loose wire shape
|
|
999
|
+
* @returns blocks in the strict saved shape
|
|
1000
|
+
*/
|
|
1001
|
+
declare function normalizeOutputBlocks(blocks: Array<OutputBlockData | LooseOutputBlockData>): OutputBlockData[];
|
|
1002
|
+
/**
|
|
1003
|
+
* Normalizes a whole loose wire document into the strict saved
|
|
1004
|
+
* {@link OutputData} shape at an input boundary. A nullish document becomes
|
|
1005
|
+
* `{ blocks: [] }`; `null` envelope fields (`time`/`version`) are dropped and a
|
|
1006
|
+
* non-empty `id` is kept; each
|
|
1007
|
+
* block is passed through {@link normalizeOutputBlocks}, so `null`/missing
|
|
1008
|
+
* `data` becomes `{}`, `null`/empty ids are dropped for regeneration and
|
|
1009
|
+
* nullish/empty `parent`/`content` references are dropped as absent.
|
|
1010
|
+
*
|
|
1011
|
+
* Unlike a hand-written `blocks.map(...)` mapper, this preserves every block
|
|
1012
|
+
* passthrough field — `tunes`, real `parent`/`content` references, `indent`,
|
|
1013
|
+
* edit metadata — so a backend DTO can be turned into strict `OutputData`
|
|
1014
|
+
* without silently losing hierarchy or tunes. Idempotent: a strict document
|
|
1015
|
+
* passes through unchanged (shallow-copied).
|
|
1016
|
+
* @param data - a document in the strict or loose wire shape, or nullish
|
|
1017
|
+
* @returns the document in the strict saved shape
|
|
1018
|
+
*/
|
|
1019
|
+
declare function normalizeOutputData(data: AnyOutputData): OutputData;
|
|
1020
|
+
/**
|
|
1021
|
+
* True when the document carries no user content: it is nullish, has no
|
|
1022
|
+
* blocks, or every block's data holds only empty values (see
|
|
1023
|
+
* {@link isEmptyValue}). Note that content-less visual blocks (e.g. a divider,
|
|
1024
|
+
* whose data is `{}`) count as empty — check `blocks.length` when mere block
|
|
1025
|
+
* presence matters.
|
|
1026
|
+
* @param data - document to inspect
|
|
1027
|
+
* @returns true when the document carries no user content
|
|
1028
|
+
*/
|
|
1029
|
+
declare function isEmptyOutputData(data: AnyOutputData): boolean;
|
|
664
1030
|
/** One field of a block's prop schema. */
|
|
665
1031
|
interface PropSchemaEntry {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
1032
|
+
/** Default value, used when the incoming data omits this key. */
|
|
1033
|
+
default: unknown;
|
|
1034
|
+
/** Optional allowed values (advisory; not enforced at runtime in v1). */
|
|
1035
|
+
values?: readonly unknown[];
|
|
670
1036
|
}
|
|
671
1037
|
/**
|
|
672
1038
|
* Declarative data shape. The keys here are EXACTLY the keys `save()` returns to
|
|
@@ -674,7 +1040,504 @@ interface PropSchemaEntry {
|
|
|
674
1040
|
* written as its explicit default, never dropped).
|
|
675
1041
|
*/
|
|
676
1042
|
type PropSchema = Record<string, PropSchemaEntry>;
|
|
677
|
-
|
|
1043
|
+
/**
|
|
1044
|
+
* Fill a data object against the schema: every schema key present, incoming
|
|
1045
|
+
* value when defined else the schema default, and ONLY schema keys (so `save()`
|
|
1046
|
+
* is never partial). Returns a frozen plain object — safe to hand straight to
|
|
1047
|
+
* core's per-key Yjs sync.
|
|
1048
|
+
*/
|
|
1049
|
+
declare const fillDefaults: <Data>(schema: PropSchema, data: Record<string, unknown>) => Readonly<Data>;
|
|
1050
|
+
/**
|
|
1051
|
+
* Every child slot carries one of these — first-party containers and every
|
|
1052
|
+
* adapter's `<BlockChildren>` alike. `BlockHierarchy` reads the same selector,
|
|
1053
|
+
* so the two sides agree on which blocks own a slot.
|
|
1054
|
+
*/
|
|
1055
|
+
declare const CHILD_SLOT_SELECTOR = "[data-blok-toggle-children], [data-blok-nested-blocks]";
|
|
1056
|
+
/**
|
|
1057
|
+
* Parents that place their children themselves (per cell / per view). Their
|
|
1058
|
+
* descendants must never be pulled into an enclosing slot.
|
|
1059
|
+
*/
|
|
1060
|
+
declare const SELF_PLACING_PARENTS: ReadonlySet<string>;
|
|
1061
|
+
/**
|
|
1062
|
+
* A slotless block renders its children as flat sibling holders right after
|
|
1063
|
+
* itself, in whatever slot holds the block — the same as nesting at root.
|
|
1064
|
+
* @param block - the block to test
|
|
1065
|
+
*/
|
|
1066
|
+
declare const isSlotless: (block: {
|
|
1067
|
+
holder: HTMLElement;
|
|
1068
|
+
name?: string;
|
|
1069
|
+
}) => boolean;
|
|
1070
|
+
/**
|
|
1071
|
+
* The blocks a container slot hosts: its children, each followed by the
|
|
1072
|
+
* descendants of a slotless child (depth-first, flat order). A child that owns a
|
|
1073
|
+
* slot keeps its own descendants.
|
|
1074
|
+
* @param children - the container block's model children, in model order
|
|
1075
|
+
* @param getChildren - model children of a block, by id
|
|
1076
|
+
*/
|
|
1077
|
+
declare const withSlotlessDescendants: <T extends {
|
|
1078
|
+
holder: HTMLElement;
|
|
1079
|
+
id?: string;
|
|
1080
|
+
name?: string;
|
|
1081
|
+
}>(children: T[], getChildren: (id: string) => T[]) => T[];
|
|
1082
|
+
/**
|
|
1083
|
+
* Mount child block holders into a container, skipping children that are
|
|
1084
|
+
* already in place or claimed by another nested-blocks container.
|
|
1085
|
+
*
|
|
1086
|
+
* Used by toggle, header, column, and callout tools — and by the React, Vue and
|
|
1087
|
+
* Angular block adapters — to reconcile child holders during the `rendered()`
|
|
1088
|
+
* lifecycle hook. It is the standing DOM↔model reconciler for container blocks:
|
|
1089
|
+
* safe to call on every render, and the only thing that heals a child holder
|
|
1090
|
+
* that core parked outside the container while the container's own slot had not
|
|
1091
|
+
* been created yet.
|
|
1092
|
+
* @param container - the container element child holders belong in; usually the
|
|
1093
|
+
* element carrying `data-blok-nested-blocks`.
|
|
1094
|
+
* @param children - the container block's MODEL children, in model order (e.g.
|
|
1095
|
+
* `api.blocks.getChildren(blockId)`).
|
|
1096
|
+
*/
|
|
1097
|
+
declare const mountChildBlocks: (container: HTMLElement, children: {
|
|
1098
|
+
holder: HTMLElement;
|
|
1099
|
+
}[]) => void;
|
|
1100
|
+
/**
|
|
1101
|
+
* One child's decoration: attribute name → value. `null`/`undefined` removes the
|
|
1102
|
+
* attribute; a boolean or number is stringified (so `false` writes
|
|
1103
|
+
* `data-active="false"`, which CSS can select, rather than dropping the hook).
|
|
1104
|
+
*/
|
|
1105
|
+
type ChildAttributes$1 = Record<string, string | number | boolean | null | undefined>;
|
|
1106
|
+
/** The minimum a child must expose for a decoration pass. */
|
|
1107
|
+
interface DecoratableChild {
|
|
1108
|
+
id: string;
|
|
1109
|
+
holder: HTMLElement;
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* A per-child decorator: what to write for the child at `index`.
|
|
1113
|
+
*
|
|
1114
|
+
* Generic over the child so an adapter can declare its decorators in terms of the
|
|
1115
|
+
* full `BlockAPI` its authors receive. A non-generic `(child: DecoratableChild)`
|
|
1116
|
+
* parameter would REJECT those: a function that demands a full BlockAPI is not
|
|
1117
|
+
* assignable to one promising to accept the structural minimum.
|
|
1118
|
+
*/
|
|
1119
|
+
type ChildAttributesFn$1<Child extends DecoratableChild = DecoratableChild> = (child: Child, index: number) => ChildAttributes$1;
|
|
1120
|
+
/** What the previous decoration pass wrote for one child, so it can be undone. */
|
|
1121
|
+
interface StampedChild {
|
|
1122
|
+
/** The element written to — a holder for one ledger, a content wrapper for the other. */
|
|
1123
|
+
target: HTMLElement;
|
|
1124
|
+
names: string[];
|
|
1125
|
+
}
|
|
1126
|
+
/** The ledgers a container keeps between passes; create one per child slot. */
|
|
1127
|
+
interface ChildDecorationLedger {
|
|
1128
|
+
holders: Map<string, StampedChild>;
|
|
1129
|
+
contents: Map<string, StampedChild>;
|
|
1130
|
+
}
|
|
1131
|
+
/**
|
|
1132
|
+
* A fresh pair of ledgers for one container's child slot.
|
|
1133
|
+
* @returns empty holder/content ledgers
|
|
1134
|
+
*/
|
|
1135
|
+
declare const createChildDecorationLedger: () => ChildDecorationLedger;
|
|
1136
|
+
/**
|
|
1137
|
+
* Decorate a container's children: named attributes on each child's HOLDER and,
|
|
1138
|
+
* separately, on each child's `[data-blok-element-content]` wrapper.
|
|
1139
|
+
*
|
|
1140
|
+
* The single implementation behind the React, Vue and Angular per-child
|
|
1141
|
+
* decoration channels, so the three cannot drift on which element a hook lands
|
|
1142
|
+
* on or on when a dropped hook is cleaned up.
|
|
1143
|
+
*
|
|
1144
|
+
* BOTH levels exist because core's child-holder decoration law blesses both, and
|
|
1145
|
+
* a container needs both: the holder is the child's outer box (rails, indices,
|
|
1146
|
+
* hover states), while the content wrapper is where the child's own text box
|
|
1147
|
+
* begins — which is what a numbered rail or a connector line has to align to.
|
|
1148
|
+
* With only the holder reachable, a container had to encode core's wrapper chain
|
|
1149
|
+
* in its own CSS (`[data-step] > [data-blok-element-content] > …`) and broke
|
|
1150
|
+
* whenever that chain changed. Neither hook may introduce an element: holders
|
|
1151
|
+
* stay DIRECT children of the slot because core's reparenting and caret
|
|
1152
|
+
* sibling checks compare `holder.parentElement` by identity.
|
|
1153
|
+
*
|
|
1154
|
+
* Both are inert with respect to change tracking: core's mutation filter drops a
|
|
1155
|
+
* holder- or content-targeted attribute record for the CHILD block (both are
|
|
1156
|
+
* ancestors of the child's tool element, not descendants) and scores it
|
|
1157
|
+
* mutation-free for the CONTAINER (whose own `data-blok-mutation-free` host is
|
|
1158
|
+
* the nearest such ancestor).
|
|
1159
|
+
* @param ledger - the slot's ledgers from {@link createChildDecorationLedger}
|
|
1160
|
+
* @param children - the container's model children, in model order
|
|
1161
|
+
* @param decorators - the authored per-child decorators
|
|
1162
|
+
* @param decorators.childAttributes - written on each child's holder
|
|
1163
|
+
* @param decorators.childContentAttributes - written on each child's content wrapper
|
|
1164
|
+
*/
|
|
1165
|
+
declare const applyChildDecoration: <Child extends DecoratableChild>(ledger: ChildDecorationLedger, children: Child[], decorators: {
|
|
1166
|
+
childAttributes?: ChildAttributesFn$1<Child>;
|
|
1167
|
+
childContentAttributes?: ChildAttributesFn$1<Child>;
|
|
1168
|
+
}) => void;
|
|
1169
|
+
/**
|
|
1170
|
+
* Centralized data attributes used across the Blok editor.
|
|
1171
|
+
* This is the single source of truth for all data-blok-* attributes.
|
|
1172
|
+
*
|
|
1173
|
+
* Exported as Blok.DATA_ATTR for users.
|
|
1174
|
+
*
|
|
1175
|
+
* Naming convention:
|
|
1176
|
+
* - Remove 'data-blok-' prefix and convert to camelCase
|
|
1177
|
+
* - Global attributes: hidden, disabled, focused
|
|
1178
|
+
* - Component prefixed: popover, popoverItem, toolbar, etc.
|
|
1179
|
+
*/
|
|
1180
|
+
declare const DATA_ATTR: {
|
|
1181
|
+
/** Interface type identifier (blok, inline-toolbar, tooltip) */
|
|
1182
|
+
readonly interface: "data-blok-interface";
|
|
1183
|
+
/** Block element wrapper */
|
|
1184
|
+
readonly element: "data-blok-element";
|
|
1185
|
+
/** Block element content wrapper */
|
|
1186
|
+
readonly elementContent: "data-blok-element-content";
|
|
1187
|
+
/** Editor wrapper container */
|
|
1188
|
+
readonly editor: "data-blok-editor";
|
|
1189
|
+
/** Per-instance discriminator on the editor wrapper (a monotonic counter, as a
|
|
1190
|
+
* string). Two editors on one page share every other scope attribute, so this
|
|
1191
|
+
* is what lets a page-level stylesheet — Blok's own injected `style.fontSize`
|
|
1192
|
+
* sheet, or a host rule — address ONE editor. Public styling hook. */
|
|
1193
|
+
readonly instance: "data-blok-instance";
|
|
1194
|
+
/** Redactor zone */
|
|
1195
|
+
readonly redactor: "data-blok-redactor";
|
|
1196
|
+
/** Present on the editor wrapper once a `blocks.render()` batch has finished
|
|
1197
|
+
* inserting blocks into the DOM; removed while a re-render is in flight.
|
|
1198
|
+
* Acts as a stable render-readiness gate for consumers (e.g. E2E waits). */
|
|
1199
|
+
readonly rendered: "data-blok-rendered";
|
|
1200
|
+
/** Present on the editor wrapper while the loading skeleton owns it.
|
|
1201
|
+
* Public styling hook. */
|
|
1202
|
+
readonly loading: "data-blok-loading";
|
|
1203
|
+
/** The loading skeleton overlay (a wrapper child, never inside the redactor). */
|
|
1204
|
+
readonly loadingSkeleton: "data-blok-loading-skeleton";
|
|
1205
|
+
/** One skeleton row; the value is its kind: heading | paragraph | list. */
|
|
1206
|
+
readonly skeletonBar: "data-blok-skeleton-bar";
|
|
1207
|
+
/** Blok version number stamped on the editor wrapper (e.g. '1.10.0', 'dev').
|
|
1208
|
+
* Consumed by browser extensions to identify the running version. */
|
|
1209
|
+
readonly version: "data-blok-version";
|
|
1210
|
+
/** Block unique identifier */
|
|
1211
|
+
readonly id: "data-blok-id";
|
|
1212
|
+
readonly pageId: "data-blok-page-id";
|
|
1213
|
+
/** Block component/tool type */
|
|
1214
|
+
readonly component: "data-blok-component";
|
|
1215
|
+
/** Tool type attribute */
|
|
1216
|
+
readonly tool: "data-blok-tool";
|
|
1217
|
+
readonly blockContextMenu: "data-blok-block-context-menu";
|
|
1218
|
+
/** Block nesting depth (derived from the parentId chain) */
|
|
1219
|
+
readonly depth: "data-blok-depth";
|
|
1220
|
+
/** Flat list-nesting indentation level (0 = root); tool-agnostic, mirrors list depth */
|
|
1221
|
+
readonly indent: "data-blok-indent";
|
|
1222
|
+
/** Header tool's heading level (1-6). Public styling hook — keyed by level rather
|
|
1223
|
+
* than by tag name, so a level remapped to a custom tag via `levelOverrides[n].tag`
|
|
1224
|
+
* (types/tools/header.d.ts) still matches its level's typography rules. */
|
|
1225
|
+
readonly headingLevel: "data-blok-heading-level";
|
|
1226
|
+
/** Element is hidden from view */
|
|
1227
|
+
readonly hidden: "data-blok-hidden";
|
|
1228
|
+
/** Element is disabled and non-interactive */
|
|
1229
|
+
readonly disabled: "data-blok-disabled";
|
|
1230
|
+
/** Element is focused via keyboard navigation */
|
|
1231
|
+
readonly focused: "data-blok-focused";
|
|
1232
|
+
/** On a popover once a navigation key moved its cursor; gates the focus ring */
|
|
1233
|
+
readonly keyboardNavigated: "data-blok-keyboard-navigated";
|
|
1234
|
+
/** Block is selected */
|
|
1235
|
+
readonly selected: "data-blok-selected";
|
|
1236
|
+
/** On a block's spotlight target while it is being pointed out (Show in the failed-image notice) */
|
|
1237
|
+
readonly spotlight: "data-blok-spotlight";
|
|
1238
|
+
/** Marks the element inside a block that Show points at, e.g. the image's error card */
|
|
1239
|
+
readonly spotlightTarget: "data-blok-spotlight-target";
|
|
1240
|
+
/** Marks the control inside a spotlight target that receives focus, e.g. Retry */
|
|
1241
|
+
readonly spotlightFocus: "data-blok-spotlight-focus";
|
|
1242
|
+
/** Block is stretched */
|
|
1243
|
+
readonly stretched: "data-blok-stretched";
|
|
1244
|
+
/** Editor or element is empty */
|
|
1245
|
+
readonly empty: "data-blok-empty";
|
|
1246
|
+
/** Present on the editor wrapper while read-only mode is active.
|
|
1247
|
+
* Public styling hook — lets hosts key rules off the editing state
|
|
1248
|
+
* without JS. Deliberately does NOT collapse the gutter: plain
|
|
1249
|
+
* read-only still shows the block-hover copy-link control there, and
|
|
1250
|
+
* in-place readOnly.set() flips must not shift the layout. */
|
|
1251
|
+
readonly readonly: "data-blok-readonly";
|
|
1252
|
+
/** Present on the editor wrapper while read-only mode hides ALL editor
|
|
1253
|
+
* controls (readOnly: { hideControls: true }). Public styling hook —
|
|
1254
|
+
* drives the gutter auto-collapse for genuinely chromeless read-only. */
|
|
1255
|
+
readonly controlsHidden: "data-blok-controls-hidden";
|
|
1256
|
+
/** Present on the editor wrapper when config.hideToolbar is true.
|
|
1257
|
+
* Public styling hook — drives the gutter auto-collapse (the gutter
|
|
1258
|
+
* exists solely to house the toolbar's +/⠿ controls). */
|
|
1259
|
+
readonly toolbarHidden: "data-blok-toolbar-hidden";
|
|
1260
|
+
/** Which gutter the floating block controls occupy: 'left' (default,
|
|
1261
|
+
* inline-start) or 'right' (inline-end). Written on the editor wrapper from
|
|
1262
|
+
* config.toolbarPosition and kept in sync by `toolbar.setPosition()`.
|
|
1263
|
+
* Public styling hook — drives the gutter swap and the actions-bar side. */
|
|
1264
|
+
readonly toolbarPosition: "data-blok-toolbar-position";
|
|
1265
|
+
/** Content alignment mode (left, center, right) */
|
|
1266
|
+
readonly contentAlign: "data-blok-content-align";
|
|
1267
|
+
/** Right-to-left mode */
|
|
1268
|
+
readonly rtl: "data-blok-rtl";
|
|
1269
|
+
/** Editor content width mode (present with value "full" for wide mode; absent = narrow) */
|
|
1270
|
+
readonly width: "data-blok-width";
|
|
1271
|
+
/** Present on the editor wrapper when config.style.nativeSelection is true.
|
|
1272
|
+
* Public styling hook — disables Blok's ::selection repaint (preflight.css)
|
|
1273
|
+
* and re-points the fake-background highlight at the UA Highlight color
|
|
1274
|
+
* (colors.css), so selection falls back to native/host-defined colors. */
|
|
1275
|
+
readonly nativeSelection: "data-blok-native-selection";
|
|
1276
|
+
/** Present on the editor wrapper while a cross-block TEXT selection is painted.
|
|
1277
|
+
* Suppresses the engine's own ::selection paint (main.css) so the
|
|
1278
|
+
* ::highlight() sub-ranges are the only thing drawn — Chromium and Firefox
|
|
1279
|
+
* paint such a range natively too and would otherwise double it up. */
|
|
1280
|
+
readonly crossSelection: "data-blok-cross-selection";
|
|
1281
|
+
/** Block is being dragged */
|
|
1282
|
+
readonly dragging: "data-blok-dragging";
|
|
1283
|
+
/** Multiple blocks being dragged */
|
|
1284
|
+
readonly draggingMulti: "data-blok-dragging-multi";
|
|
1285
|
+
/** Block is being duplicated (Alt+drag) */
|
|
1286
|
+
readonly duplicating: "data-blok-duplicating";
|
|
1287
|
+
/** Drag handle element */
|
|
1288
|
+
readonly dragHandle: "data-blok-drag-handle";
|
|
1289
|
+
/** Toolbar element */
|
|
1290
|
+
readonly toolbar: "data-blok-toolbar";
|
|
1291
|
+
/** The floating block-controls bar (plus button + drag/settings handle)
|
|
1292
|
+
* inside the toolbar. Public styling hook — the side it docks to is driven
|
|
1293
|
+
* from the wrapper's `data-blok-toolbar-position`. */
|
|
1294
|
+
readonly toolbarActions: "data-blok-toolbar-actions";
|
|
1295
|
+
/** Settings toggler button */
|
|
1296
|
+
readonly settingsToggler: "data-blok-settings-toggler";
|
|
1297
|
+
/** Toolbox is open */
|
|
1298
|
+
readonly toolboxOpened: "data-blok-toolbox-opened";
|
|
1299
|
+
/** Block settings is open */
|
|
1300
|
+
readonly blockSettingsOpened: "data-blok-block-settings-opened";
|
|
1301
|
+
/** Element is opened (generic) */
|
|
1302
|
+
readonly opened: "data-blok-opened";
|
|
1303
|
+
/** Root popover element */
|
|
1304
|
+
readonly popover: "data-blok-popover";
|
|
1305
|
+
/** Popover container wrapper */
|
|
1306
|
+
readonly popoverContainer: "data-blok-popover-container";
|
|
1307
|
+
/** Popover items list */
|
|
1308
|
+
readonly popoverItems: "data-blok-popover-items";
|
|
1309
|
+
/** Custom, engine-independent scrollbar thumb overlaid on the popover items */
|
|
1310
|
+
readonly popoverScrollbar: "data-blok-popover-scrollbar";
|
|
1311
|
+
/** Stamped on the custom scrollbar thumb while it is being dragged (keeps it revealed) */
|
|
1312
|
+
readonly popoverScrollbarDragging: "data-blok-dragging";
|
|
1313
|
+
/** Stamped on a scroll container while it is actively scrolling (reveals the auto-hidden scrollbar thumb) */
|
|
1314
|
+
readonly scrolling: "data-blok-scrolling";
|
|
1315
|
+
/** Popover overlay element */
|
|
1316
|
+
readonly popoverOverlay: "data-blok-popover-overlay";
|
|
1317
|
+
/** Popover custom content area */
|
|
1318
|
+
readonly popoverCustomContent: "data-blok-popover-custom-content";
|
|
1319
|
+
/** Popover custom class */
|
|
1320
|
+
readonly popoverCustomClass: "data-blok-popover-custom-class";
|
|
1321
|
+
/** Inline popover variant */
|
|
1322
|
+
readonly popoverInline: "data-blok-popover-inline";
|
|
1323
|
+
/** Popover is open */
|
|
1324
|
+
readonly popoverOpened: "data-blok-popover-opened";
|
|
1325
|
+
/** Popover opens upward */
|
|
1326
|
+
readonly popoverOpenTop: "data-blok-popover-open-top";
|
|
1327
|
+
/** Popover opens leftward */
|
|
1328
|
+
readonly popoverOpenLeft: "data-blok-popover-open-left";
|
|
1329
|
+
/** Nested popover indicator */
|
|
1330
|
+
readonly nested: "data-blok-nested";
|
|
1331
|
+
/** Nesting level value */
|
|
1332
|
+
readonly nestedLevel: "data-blok-nested-level";
|
|
1333
|
+
/** Group label for promoted search results from nested children */
|
|
1334
|
+
readonly promotedGroupLabel: "data-blok-promoted-group-label";
|
|
1335
|
+
/** A nested child shown in the host menu's search results. The convert-menu styles skip it, so the host keeps its own layout. */
|
|
1336
|
+
readonly promotedItem: "data-blok-promoted-item";
|
|
1337
|
+
/** Group label for top-level matches in search results */
|
|
1338
|
+
readonly topLevelGroupLabel: "data-blok-top-level-group-label";
|
|
1339
|
+
/** Header container */
|
|
1340
|
+
readonly popoverHeader: "data-blok-popover-header";
|
|
1341
|
+
/** Header text element */
|
|
1342
|
+
readonly popoverHeaderText: "data-blok-popover-header-text";
|
|
1343
|
+
/** Back button in nested popover */
|
|
1344
|
+
readonly popoverHeaderBackButton: "data-blok-popover-header-back-button";
|
|
1345
|
+
/** Item container */
|
|
1346
|
+
readonly popoverItem: "data-blok-popover-item";
|
|
1347
|
+
/** Item icon wrapper */
|
|
1348
|
+
readonly popoverItemIcon: "data-blok-popover-item-icon";
|
|
1349
|
+
/** Chevron icon for nested items */
|
|
1350
|
+
readonly popoverItemIconChevronRight: "data-blok-popover-item-icon-chevron-right";
|
|
1351
|
+
/** Item title text */
|
|
1352
|
+
readonly popoverItemTitle: "data-blok-popover-item-title";
|
|
1353
|
+
/** Item secondary title */
|
|
1354
|
+
readonly popoverItemSecondaryTitle: "data-blok-popover-item-secondary-title";
|
|
1355
|
+
/** Item is active/selected */
|
|
1356
|
+
readonly popoverItemActive: "data-blok-popover-item-active";
|
|
1357
|
+
/** Item's child menu is currently open — keeps the trigger looking selected */
|
|
1358
|
+
readonly popoverItemChildrenOpen: "data-blok-popover-item-children-open";
|
|
1359
|
+
/** Confirmation state */
|
|
1360
|
+
readonly popoverItemConfirmation: "data-blok-popover-item-confirmation";
|
|
1361
|
+
/** Disable hover styling */
|
|
1362
|
+
readonly popoverItemNoHover: "data-blok-popover-item-no-hover";
|
|
1363
|
+
/** Disable focus handling */
|
|
1364
|
+
readonly popoverItemNoFocus: "data-blok-popover-item-no-focus";
|
|
1365
|
+
/** Destructive action item (e.g. delete) */
|
|
1366
|
+
readonly popoverItemDestructive: "data-blok-popover-item-destructive";
|
|
1367
|
+
/** Separator item */
|
|
1368
|
+
readonly popoverItemSeparator: "data-blok-popover-item-separator";
|
|
1369
|
+
/** Separator line element */
|
|
1370
|
+
readonly popoverItemSeparatorLine: "data-blok-popover-item-separator-line";
|
|
1371
|
+
/** HTML-based item */
|
|
1372
|
+
readonly popoverItemHtml: "data-blok-popover-item-html";
|
|
1373
|
+
/** Item has child menu */
|
|
1374
|
+
readonly hasChildren: "data-blok-has-children";
|
|
1375
|
+
/** Item name identifier */
|
|
1376
|
+
readonly itemName: "data-blok-item-name";
|
|
1377
|
+
/** No search results shown */
|
|
1378
|
+
readonly nothingFoundDisplayed: "data-blok-nothing-found-displayed";
|
|
1379
|
+
/** Selection overlay */
|
|
1380
|
+
readonly overlay: "data-blok-overlay";
|
|
1381
|
+
/** Overlay container */
|
|
1382
|
+
readonly overlayContainer: "data-blok-overlay-container";
|
|
1383
|
+
/** Selection rectangle */
|
|
1384
|
+
readonly overlayRectangle: "data-blok-overlay-rectangle";
|
|
1385
|
+
/** Overlay is hidden */
|
|
1386
|
+
readonly overlayHidden: "data-blok-overlay-hidden";
|
|
1387
|
+
/** Fake cursor indicator */
|
|
1388
|
+
readonly fakeCursor: "data-blok-fake-cursor";
|
|
1389
|
+
/** Fake background for selection */
|
|
1390
|
+
readonly fakeBackground: "data-blok-fake-background";
|
|
1391
|
+
/** Auto-scroll zone (top/bottom) */
|
|
1392
|
+
readonly scrollZone: "data-blok-scroll-zone";
|
|
1393
|
+
/** Scroll is locked */
|
|
1394
|
+
readonly scrollLocked: "data-blok-scroll-locked";
|
|
1395
|
+
/** Hard scroll lock */
|
|
1396
|
+
readonly scrollLockedHard: "data-blok-scroll-locked-hard";
|
|
1397
|
+
/** Shadow caret element */
|
|
1398
|
+
readonly shadowCaret: "data-blok-shadow-caret";
|
|
1399
|
+
/** Placeholder text */
|
|
1400
|
+
readonly placeholder: "data-blok-placeholder";
|
|
1401
|
+
/** Active placeholder text */
|
|
1402
|
+
readonly placeholderActive: "data-blok-placeholder-active";
|
|
1403
|
+
/** The columns row rendered by the column_list tool (the flex container).
|
|
1404
|
+
* Public styling hook — its direct `[data-blok-element]` children are the
|
|
1405
|
+
* column holders, whose shrink floor reads `--blok-column-min-width` and
|
|
1406
|
+
* whose gutter reads `--blok-column-gutter`. */
|
|
1407
|
+
readonly columns: "data-blok-columns";
|
|
1408
|
+
/** A single column inside a columns row. */
|
|
1409
|
+
readonly column: "data-blok-column";
|
|
1410
|
+
/** Drag-to-resize separator between two adjacent columns. Present only in
|
|
1411
|
+
* edit mode — the separators ARE the gutter there. */
|
|
1412
|
+
readonly columnResizer: "data-blok-column-resizer";
|
|
1413
|
+
/** Present on a columns row whose gutter comes from the container's own
|
|
1414
|
+
* column-gap instead of from resizer elements. Set in read-only mode, where
|
|
1415
|
+
* no resizers are built — the discriminator between an editable row and a
|
|
1416
|
+
* published one. */
|
|
1417
|
+
readonly columnsStaticGutter: "data-blok-columns-static-gutter";
|
|
1418
|
+
/** Container that hosts nested block holders (table cells, toggle/callout/header children).
|
|
1419
|
+
* Used as a universal guard: before moving a block holder via appendChild,
|
|
1420
|
+
* check `holder.closest([nestedBlocks])` — if truthy, the holder is already
|
|
1421
|
+
* claimed by another container and must not be stolen. */
|
|
1422
|
+
readonly nestedBlocks: "data-blok-nested-blocks";
|
|
1423
|
+
/** A drop zone. Empty value: an empty container's placeholder (an empty
|
|
1424
|
+
* tab); while the block's own holder shows one without the `hidden` class,
|
|
1425
|
+
* a drop on the block nests the dragged blocks as its first children.
|
|
1426
|
+
* A block id (a tab pill): a drop on the zone appends the dragged blocks
|
|
1427
|
+
* as the LAST children of that block. */
|
|
1428
|
+
readonly dropInto: "data-blok-drop-into";
|
|
1429
|
+
/** Set by core on a named drop zone while it is the drop target. */
|
|
1430
|
+
readonly dropIntoActive: "data-blok-drop-into-active";
|
|
1431
|
+
/** A container's empty-state hint that stands in for its first child block
|
|
1432
|
+
* (empty tab, empty toggle body). It is not a block, so hovering or pressing
|
|
1433
|
+
* it shows no block toolbar; the block a click creates gets its own. */
|
|
1434
|
+
readonly childStandIn: "data-blok-child-stand-in";
|
|
1435
|
+
/** Element excluded from mutation tracking */
|
|
1436
|
+
readonly mutationFree: "data-blok-mutation-free";
|
|
1437
|
+
/** Tool UI inside a block that is not the user's content (a list marker, a
|
|
1438
|
+
* checkbox, a code block's language button and line numbers). `Block.isEmpty`
|
|
1439
|
+
* and the block's copied HTML skip it. Never put it on an element that holds
|
|
1440
|
+
* child blocks or the user's text: that content would be skipped too. */
|
|
1441
|
+
readonly chrome: "data-blok-chrome";
|
|
1442
|
+
/** Marks a subtree whose keyboard belongs to the Tool that rendered it, not to
|
|
1443
|
+
* the editor. Blok's block-level keydown/keyup handling stands down entirely
|
|
1444
|
+
* for events originating inside it — Escape, Tab, the arrows, "/" and the
|
|
1445
|
+
* Enter/Backspace/Delete structural keys all reach the element untouched.
|
|
1446
|
+
*
|
|
1447
|
+
* Blok already exempts native `<input>`/`<textarea>` from the STRUCTURAL keys
|
|
1448
|
+
* (Enter/Backspace/Delete and "/") because those are contenteditable-shaped
|
|
1449
|
+
* and would splice the document around a form field. Escape/Tab/arrows are
|
|
1450
|
+
* deliberately NOT exempt — they are how a user leaves a field. That default
|
|
1451
|
+
* is right for a one-line title input and wrong for a field with its own
|
|
1452
|
+
* keyboard semantics (Tab between sub-fields, Escape to cancel an edit, arrows
|
|
1453
|
+
* to walk a suggestion list), which is exactly what this attribute is for.
|
|
1454
|
+
* Public authoring hook. */
|
|
1455
|
+
readonly keyboardOwner: "data-blok-keyboard-owner";
|
|
1456
|
+
/** Marks a subtree whose links belong to the tool: Blok's link hover card
|
|
1457
|
+
* and link-click navigation stand down inside it. For a link the tool opens
|
|
1458
|
+
* and previews itself (the page block). Public authoring hook. */
|
|
1459
|
+
readonly linkOwner: "data-blok-link-owner";
|
|
1460
|
+
/** Block has navigation focus */
|
|
1461
|
+
readonly navigationFocused: "data-blok-navigation-focused";
|
|
1462
|
+
/** Flipper navigation target */
|
|
1463
|
+
readonly flipperNavigationTarget: "data-blok-flipper-navigation-target";
|
|
1464
|
+
/** Inline toolbar enabled on external element */
|
|
1465
|
+
readonly inlineToolbar: "data-blok-inline-toolbar";
|
|
1466
|
+
/** Link tool is active */
|
|
1467
|
+
readonly linkToolActive: "data-blok-link-tool-active";
|
|
1468
|
+
/** Link tool unlink mode */
|
|
1469
|
+
readonly linkToolUnlink: "data-blok-link-tool-unlink";
|
|
1470
|
+
/** Link tool input is opened */
|
|
1471
|
+
readonly linkToolInputOpened: "data-blok-link-tool-input-opened";
|
|
1472
|
+
/** Bold collapsed length tracking */
|
|
1473
|
+
readonly boldCollapsedLength: "data-blok-bold-collapsed-length";
|
|
1474
|
+
/** Bold collapsed active state */
|
|
1475
|
+
readonly boldCollapsedActive: "data-blok-bold-collapsed-active";
|
|
1476
|
+
/** Bold previous length tracking */
|
|
1477
|
+
readonly boldPrevLength: "data-blok-bold-prev-length";
|
|
1478
|
+
/** Bold leading whitespace */
|
|
1479
|
+
readonly boldLeadingWs: "data-blok-bold-leading-ws";
|
|
1480
|
+
/** Bold marker */
|
|
1481
|
+
readonly boldMarker: "data-blok-bold-marker";
|
|
1482
|
+
/** Tooltip is shown */
|
|
1483
|
+
readonly shown: "data-blok-shown";
|
|
1484
|
+
/** Tooltip placement */
|
|
1485
|
+
readonly placement: "data-blok-placement";
|
|
1486
|
+
/** Bounce in animation */
|
|
1487
|
+
readonly bounceIn: "data-blok-bounce-in";
|
|
1488
|
+
/** Live region announcer */
|
|
1489
|
+
readonly announcer: "data-blok-announcer";
|
|
1490
|
+
/** Stub block element */
|
|
1491
|
+
readonly stub: "data-blok-stub";
|
|
1492
|
+
/** Stub info section */
|
|
1493
|
+
readonly stubInfo: "data-blok-stub-info";
|
|
1494
|
+
/** Stub title */
|
|
1495
|
+
readonly stubTitle: "data-blok-stub-title";
|
|
1496
|
+
/** Stub subtitle */
|
|
1497
|
+
readonly stubSubtitle: "data-blok-stub-subtitle";
|
|
1498
|
+
/** Slash search active on content editable */
|
|
1499
|
+
readonly slashSearch: "data-blok-slash-search";
|
|
1500
|
+
/** Test identifier (for E2E tests) */
|
|
1501
|
+
readonly testid: "data-blok-testid";
|
|
1502
|
+
/** Force hover state (for tests/storybook) */
|
|
1503
|
+
readonly forceHover: "data-blok-force-hover";
|
|
1504
|
+
};
|
|
1505
|
+
/**
|
|
1506
|
+
* Type for DATA_ATTR keys
|
|
1507
|
+
*/
|
|
1508
|
+
type DataAttrKey = keyof typeof DATA_ATTR;
|
|
1509
|
+
/**
|
|
1510
|
+
* Type for DATA_ATTR values
|
|
1511
|
+
*/
|
|
1512
|
+
type DataAttrValue = (typeof DATA_ATTR)[DataAttrKey];
|
|
1513
|
+
/**
|
|
1514
|
+
* Helper function to create a CSS selector from an attribute
|
|
1515
|
+
*
|
|
1516
|
+
* @param attr - The data attribute name from DATA_ATTR
|
|
1517
|
+
* @param value - Optional value for the attribute (defaults to presence selector)
|
|
1518
|
+
* @returns CSS selector string
|
|
1519
|
+
*
|
|
1520
|
+
* @example
|
|
1521
|
+
* createSelector(DATA_ATTR.element) // '[data-blok-element]'
|
|
1522
|
+
* createSelector(DATA_ATTR.selected, true) // '[data-blok-selected="true"]'
|
|
1523
|
+
* createSelector(DATA_ATTR.tool, 'paragraph') // '[data-blok-tool="paragraph"]'
|
|
1524
|
+
*/
|
|
1525
|
+
declare const createSelector: (attr: DataAttrValue, value?: string | boolean) => string;
|
|
1526
|
+
/**
|
|
1527
|
+
* Fired when a CONTAINER block's child holders have been mounted into its
|
|
1528
|
+
* child slot — the moment the child DOM has settled and a caret set into a
|
|
1529
|
+
* freshly inserted child sticks.
|
|
1530
|
+
*
|
|
1531
|
+
* Emitted by the React, Vue and Angular block adapters, whose portals commit a
|
|
1532
|
+
* frame AFTER core's `rendered()` hook; a vanilla container tool mounts its
|
|
1533
|
+
* children synchronously inside `rendered()`, so for those `block:rendered`
|
|
1534
|
+
* already means "settled". It fires on every reconciliation pass of the slot,
|
|
1535
|
+
* not only the first, so treat it as a settle signal rather than a change
|
|
1536
|
+
* signal.
|
|
1537
|
+
*
|
|
1538
|
+
* Public event name: `block:childrenMounted`.
|
|
1539
|
+
*/
|
|
1540
|
+
declare const BlockChildrenMounted = "block:childrenMounted";
|
|
678
1541
|
/**
|
|
679
1542
|
* Every STATIC member of core's block-tool contract an Angular block may declare
|
|
680
1543
|
* for itself — `ownsChildren`, `keepsChildrenOnEnter`, `conversionConfig`,
|
|
@@ -694,117 +1557,126 @@ type BlockToolStatics = Omit<BlockToolConstructable, 'toolbox' | 'isReadOnlySupp
|
|
|
694
1557
|
* off its own `BlockAPI`.
|
|
695
1558
|
*/
|
|
696
1559
|
interface AngularBlockMountedContext {
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
1560
|
+
/**
|
|
1561
|
+
* Why this block instance was constructed: a CREATION origin (`user`, `api`,
|
|
1562
|
+
* `convert`) means the author just made it, so seeding default children is
|
|
1563
|
+
* correct; a RESTORE origin (`load`, `replay`, `paste`) means the document
|
|
1564
|
+
* already says what the children are. `probe` is an off-tree instance built
|
|
1565
|
+
* only to read a tool's default data — it must not touch the block tree at
|
|
1566
|
+
* all. Defaults to `'api'` when the constructor was handed no origin.
|
|
1567
|
+
*/
|
|
1568
|
+
origin: BlockOrigin;
|
|
1569
|
+
/** The editor-level API (`api.blocks`, `api.caret`, `api.events`…). */
|
|
1570
|
+
api: API;
|
|
708
1571
|
}
|
|
709
1572
|
/** Spec for {@link createAngularBlock}. Authored as a standalone component. */
|
|
710
1573
|
interface CreateAngularBlockSpec<Data = BlockToolData> {
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
1574
|
+
/** Tool type name (registered key). */
|
|
1575
|
+
type: string;
|
|
1576
|
+
/** Optional toolbox entry. */
|
|
1577
|
+
toolbox?: ToolboxConfig;
|
|
1578
|
+
/** Declarative defaults that also define the exact `save()` key set. */
|
|
1579
|
+
propSchema: PropSchema;
|
|
1580
|
+
/**
|
|
1581
|
+
* The standalone Angular component to render for each block. It injects the
|
|
1582
|
+
* per-block context via `inject(BLOK_BLOCK_CONTEXT)`.
|
|
1583
|
+
*/
|
|
1584
|
+
component: Type<unknown>;
|
|
1585
|
+
/**
|
|
1586
|
+
* Static members of core's tool contract, forwarded verbatim onto the
|
|
1587
|
+
* generated tool class — the single channel for everything core reads off the
|
|
1588
|
+
* CLASS rather than the instance (`ownsChildren`, `keepsChildrenOnEnter`,
|
|
1589
|
+
* `conversionConfig`, `pasteConfig`, `sanitize`, `shortcut`, `upgradeData`…).
|
|
1590
|
+
* Without it the only way to declare one was to subclass the generated class.
|
|
1591
|
+
*
|
|
1592
|
+
* `keepsChildrenOnEnter` is the per-tool Enter POLICY: declare it and Enter on
|
|
1593
|
+
* this container's empty LAST child creates the new line INSIDE the container
|
|
1594
|
+
* instead of escaping to the container's parent (Blok's default, which is
|
|
1595
|
+
* Notion's callout behaviour). Core cannot read that off the DOM — a callout
|
|
1596
|
+
* renders the same `data-blok-nested-blocks` slot as a column yet wants the
|
|
1597
|
+
* escape — so before it existed a layout container (a card, a `steps` block)
|
|
1598
|
+
* had to hijack the editor-global `config.onEnter` and re-derive containment.
|
|
1599
|
+
*
|
|
1600
|
+
* `toolbox` and `isReadOnlySupported` are owned by the factory and cannot be
|
|
1601
|
+
* overridden here (see {@link BlockToolStatics}).
|
|
1602
|
+
*/
|
|
1603
|
+
statics?: BlockToolStatics;
|
|
1604
|
+
/**
|
|
1605
|
+
* The element the +/drag toolbar should vertically center on — core's
|
|
1606
|
+
* `getToolbarAnchorElement` hook, resolved against this block's host element
|
|
1607
|
+
* on every call (never cached, so it tracks re-renders).
|
|
1608
|
+
*
|
|
1609
|
+
* A container block whose own chrome is not editable needs it: with no anchor,
|
|
1610
|
+
* core centers the toolbar on the first `[contenteditable]` under the host,
|
|
1611
|
+
* which for a container is its FIRST CHILD BLOCK. Return `null`/`undefined`
|
|
1612
|
+
* (or omit the field) to keep core's default.
|
|
1613
|
+
* @param host - this block's mutation-free host element
|
|
1614
|
+
* @param block - this block's per-block API
|
|
1615
|
+
*/
|
|
1616
|
+
getToolbarAnchorElement?: (host: HTMLElement, block: BlockAPI) => HTMLElement | null | undefined;
|
|
1617
|
+
/**
|
|
1618
|
+
* Enter (or Cmd/Ctrl+Enter) on this block while it is the keyboard
|
|
1619
|
+
* navigation target — core's `onNavigationEnter` hook. Return true when the
|
|
1620
|
+
* block handled it (e.g. opened a link); omit it, or return false, to let
|
|
1621
|
+
* core put the caret in the block.
|
|
1622
|
+
* @param event - the Enter keydown
|
|
1623
|
+
* @param block - this block's per-block API
|
|
1624
|
+
*/
|
|
1625
|
+
onNavigationEnter?: (event: KeyboardEvent, block: BlockAPI) => boolean;
|
|
1626
|
+
/** Optional lifecycle callbacks mapped from Blok's block hooks. */
|
|
1627
|
+
onRendered?: (block: BlockAPI) => void;
|
|
1628
|
+
/**
|
|
1629
|
+
* Fired ONCE per block instance, once the component's DOM (and, for a
|
|
1630
|
+
* container, the child holders its `ctx.mountChildren` adopted) exists.
|
|
1631
|
+
* Angular mounts the block synchronously while core is still inside
|
|
1632
|
+
* `render()`, so this lands with `rendered()` — the first hook at which the
|
|
1633
|
+
* host is also in the document. The React and Vue adapters spell the same
|
|
1634
|
+
* contract; there it is genuinely LATER than `onRendered`, because their
|
|
1635
|
+
* portals commit a frame after core returns.
|
|
1636
|
+
*
|
|
1637
|
+
* It is also the create-vs-restore signal: `context.origin` says whether the
|
|
1638
|
+
* author just made this block (`user`/`api`/`convert`) or the document is
|
|
1639
|
+
* being re-materialised (`load`/`replay`/`paste`) — so a container can seed
|
|
1640
|
+
* its default children here exactly once, without the "children are
|
|
1641
|
+
* transiently empty during a replay" trap.
|
|
1642
|
+
* @example
|
|
1643
|
+
* ```ts
|
|
1644
|
+
* onMounted: (block, { origin, api }) => {
|
|
1645
|
+
* if (origin === 'user' && block.getChildren().length === 0) {
|
|
1646
|
+
* api.blocks.insertInsideParent(block.id);
|
|
1647
|
+
* }
|
|
1648
|
+
* }
|
|
1649
|
+
* ```
|
|
1650
|
+
*/
|
|
1651
|
+
onMounted?: (block: BlockAPI, context: AngularBlockMountedContext) => void;
|
|
1652
|
+
/**
|
|
1653
|
+
* The SEEDING hook: `onMounted`, narrowed to a genuine creation. Fired ONCE
|
|
1654
|
+
* per block instance, once the component's DOM exists, and only when this
|
|
1655
|
+
* instance is the author making a new block (`origin` of `user`, `api` or
|
|
1656
|
+
* `convert`) — never for a `load`/`replay`/`paste` restore, and never for the
|
|
1657
|
+
* off-tree `probe` instance core builds to read a tool's default data.
|
|
1658
|
+
*
|
|
1659
|
+
* That predicate is why the hook exists rather than leaving every block to
|
|
1660
|
+
* read `context.origin` in `onMounted`: the intuitive `origin === 'user'` test
|
|
1661
|
+
* is wrong. It drops `api.blocks.insert('steps')` and turn-into, so a
|
|
1662
|
+
* container seeded that way comes up empty for every path except a keystroke.
|
|
1663
|
+
* Core refused to ship that axis into its own `column`/`column_list`; this
|
|
1664
|
+
* encodes the correct one once, here.
|
|
1665
|
+
*
|
|
1666
|
+
* The `context` is the same object {@link CreateAngularBlockSpec.onMounted}
|
|
1667
|
+
* receives, so a block that only seeds can read `origin` for finer decisions.
|
|
1668
|
+
* @example
|
|
1669
|
+
* ```ts
|
|
1670
|
+
* onCreated: (block, { api }) => {
|
|
1671
|
+
* if (block.getChildren().length === 0) {
|
|
1672
|
+
* api.blocks.insertInsideParent(block.id);
|
|
1673
|
+
* }
|
|
1674
|
+
* }
|
|
1675
|
+
* ```
|
|
1676
|
+
*/
|
|
1677
|
+
onCreated?: (block: BlockAPI, context: AngularBlockMountedContext) => void;
|
|
1678
|
+
onMoved?: (block: BlockAPI) => void;
|
|
1679
|
+
onRemoved?: (block: BlockAPI) => void;
|
|
808
1680
|
}
|
|
809
1681
|
/**
|
|
810
1682
|
* Author a first-party Angular block. Returns a `BlockToolConstructable`
|
|
@@ -822,43 +1694,43 @@ interface CreateAngularBlockSpec<Data = BlockToolData> {
|
|
|
822
1694
|
* - `setReadOnly()` flips a reactive flag and flushes CD (in-place, no remount).
|
|
823
1695
|
* - `removed()`/`destroy()` unregister the portal (deterministic unmount).
|
|
824
1696
|
*/
|
|
825
|
-
declare function createAngularBlock<Data = BlockToolData>(spec: CreateAngularBlockSpec<Data>): (new (options: BlockToolConstructorOptions) => {
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
1697
|
+
export declare function createAngularBlock<Data = BlockToolData>(spec: CreateAngularBlockSpec<Data>): (new (options: BlockToolConstructorOptions) => {
|
|
1698
|
+
render(): HTMLElement;
|
|
1699
|
+
save(): BlockToolData;
|
|
1700
|
+
setData(newData: BlockToolData): Promise<boolean>;
|
|
1701
|
+
setReadOnly(state: boolean): void;
|
|
1702
|
+
getToolbarAnchorElement(): HTMLElement | undefined;
|
|
1703
|
+
onNavigationEnter(event: KeyboardEvent): boolean;
|
|
1704
|
+
rendered(): void;
|
|
1705
|
+
moved(): void;
|
|
1706
|
+
removed(): void;
|
|
1707
|
+
destroy(): void;
|
|
835
1708
|
}) & BlockToolStatics & {
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
1709
|
+
readonly __isBlokAngularBlock: true;
|
|
1710
|
+
readonly toolbox: ToolboxConfig | undefined;
|
|
1711
|
+
readonly isReadOnlySupported: boolean;
|
|
839
1712
|
};
|
|
840
|
-
|
|
841
1713
|
/** Options for {@link injectBlocks}. */
|
|
842
1714
|
interface InjectBlocksOptions {
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
1715
|
+
/**
|
|
1716
|
+
* Invalidate reads only for changes inside the subtree rooted at this block id
|
|
1717
|
+
* (the block itself or any descendant). Omit — or pass `null` — for the
|
|
1718
|
+
* document-wide default.
|
|
1719
|
+
*
|
|
1720
|
+
* This bounds REACTIVITY, not reads: the returned API still sees the whole
|
|
1721
|
+
* tree, so a scoped consumer can still `getById` anything. Reach for it in a
|
|
1722
|
+
* container block that renders only its own children — unscoped, such a block
|
|
1723
|
+
* invalidates on every keystroke anywhere in the document, and a page of N
|
|
1724
|
+
* containers turns one keystroke into N re-renders.
|
|
1725
|
+
*
|
|
1726
|
+
* Accepted as a plain value or a signal (like `editor`) and read at EMIT time,
|
|
1727
|
+
* so changing it takes effect immediately with no re-subscription.
|
|
1728
|
+
*
|
|
1729
|
+
* A change whose block cannot be placed in the tree (a removal that emits
|
|
1730
|
+
* after the block is gone) counts as in-scope: skipping it would leave a
|
|
1731
|
+
* container rendering a child that no longer exists.
|
|
1732
|
+
*/
|
|
1733
|
+
within?: Signal<string | null> | string | null;
|
|
862
1734
|
}
|
|
863
1735
|
/**
|
|
864
1736
|
* Angular factory exposing an id/parentId-relative, reactive view of the block
|
|
@@ -896,30 +1768,29 @@ interface InjectBlocksOptions {
|
|
|
896
1768
|
* @param options - reactivity options; see {@link InjectBlocksOptions.within} to
|
|
897
1769
|
* scope invalidation to one block's subtree
|
|
898
1770
|
*/
|
|
899
|
-
declare function injectBlocks(editor: Signal<Blok | null>, options?: InjectBlocksOptions): UseBlocksApi;
|
|
900
|
-
|
|
1771
|
+
export declare function injectBlocks(editor: Signal<Blok | null>, options?: InjectBlocksOptions): UseBlocksApi;
|
|
901
1772
|
/** How the caller names the DOM scope to observe. */
|
|
902
1773
|
type BlokReadyScope = (() => Element | ElementRef<Element> | null | undefined) | ElementRef<Element> | Element | null;
|
|
903
1774
|
/** Options accepted by {@link injectBlokReady}. */
|
|
904
1775
|
interface InjectBlokReadyOptions {
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
1776
|
+
/**
|
|
1777
|
+
* Restrict the wait to editors mounted inside this element. Accepts an
|
|
1778
|
+
* element, an `ElementRef`, or a getter/signal returning either — the getter
|
|
1779
|
+
* form lets you pass `() => this.scopeRef?.nativeElement` from a field
|
|
1780
|
+
* initializer, before the view exists. It is re-read on every readiness
|
|
1781
|
+
* change.
|
|
1782
|
+
*
|
|
1783
|
+
* Omit it to observe every editor on the page. Passing it while it still
|
|
1784
|
+
* resolves to null reports NOT ready — an unresolved scope must never fall
|
|
1785
|
+
* back to the page-global one.
|
|
1786
|
+
*/
|
|
1787
|
+
within?: BlokReadyScope;
|
|
1788
|
+
/**
|
|
1789
|
+
* `'ready'` (default) settles when each editor has finished booting.
|
|
1790
|
+
* `'rendered'` also waits for its content to be in the DOM and re-arms on
|
|
1791
|
+
* every post-boot re-render.
|
|
1792
|
+
*/
|
|
1793
|
+
settleOn?: 'ready' | 'rendered';
|
|
923
1794
|
}
|
|
924
1795
|
/**
|
|
925
1796
|
* Angular factory exposing the live readiness of the Blok editors in a DOM
|
|
@@ -937,8 +1808,7 @@ interface InjectBlokReadyOptions {
|
|
|
937
1808
|
* `@ViewChild` scope to exist. Over-waiting is safe; under-waiting is a bug.
|
|
938
1809
|
* @param options - scope and readiness depth
|
|
939
1810
|
*/
|
|
940
|
-
declare function injectBlokReady(options?: InjectBlokReadyOptions): Signal<boolean>;
|
|
941
|
-
|
|
1811
|
+
export declare function injectBlokReady(options?: InjectBlokReadyOptions): Signal<boolean>;
|
|
942
1812
|
/**
|
|
943
1813
|
* One child's decoration: attribute name → value. `null`/`undefined` removes the
|
|
944
1814
|
* attribute; a boolean or number is stringified (so `false` writes
|
|
@@ -954,88 +1824,87 @@ type ChildAttributesFn = (child: BlockAPI, index: number) => ChildAttributes;
|
|
|
954
1824
|
* JIT test harness. The ONLY data write path is `commit`.
|
|
955
1825
|
*/
|
|
956
1826
|
interface AngularBlockRenderContext<Data> {
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1827
|
+
/** Reactive, FROZEN snapshot of the block data. Read `data()`; never mutate. */
|
|
1828
|
+
data: Signal<Readonly<Data>>;
|
|
1829
|
+
/** The ONLY data write path: merge a partial patch and sync once. */
|
|
1830
|
+
commit: (patch: Partial<Data>) => void;
|
|
1831
|
+
/** This block's per-block API (id, getChildren, dispatchChange…). */
|
|
1832
|
+
block: BlockAPI;
|
|
1833
|
+
/**
|
|
1834
|
+
* The EDITOR-level API this block belongs to (`api.blocks`, `api.caret`,
|
|
1835
|
+
* `api.toolbar`…) — the same object a vanilla tool receives in its
|
|
1836
|
+
* constructor. Reach for it when a block has to drive the document around it
|
|
1837
|
+
* instead of routing everything through `block.call()` string dispatch.
|
|
1838
|
+
*
|
|
1839
|
+
* For the reactive, id/parentId-relative view of the tree (and to re-render
|
|
1840
|
+
* when your own children change), pair `injectBlocks` with
|
|
1841
|
+
* `injectBlokInstance()` instead — the api handle itself is not reactive.
|
|
1842
|
+
*/
|
|
1843
|
+
api: API;
|
|
1844
|
+
/**
|
|
1845
|
+
* Reactive read-only flag. Read `readOnly()` in the template to disable
|
|
1846
|
+
* editing (drop `contenteditable`, hide controls). Toggled IN PLACE by core's
|
|
1847
|
+
* read-only switch — the component reacts without a remount, so ephemeral
|
|
1848
|
+
* state survives. A block that ignores it stays interactive when the editor is
|
|
1849
|
+
* read-only (same contract as a vanilla tool's `setReadOnly`).
|
|
1850
|
+
*/
|
|
1851
|
+
readOnly: Signal<boolean>;
|
|
1852
|
+
/**
|
|
1853
|
+
* Container blocks only: append this block's real child holders into `host`
|
|
1854
|
+
* (a `data-blok-nested` element the author owns). Call it once in
|
|
1855
|
+
* `ngAfterViewInit`; the factory re-runs the same mount on every data change
|
|
1856
|
+
* so late-added children appear. Angular must NOT manage these child holders.
|
|
1857
|
+
*
|
|
1858
|
+
* `childAttributes` decorates each child's HOLDER after the holders are
|
|
1859
|
+
* mounted, and is REMEMBERED — every later remount re-applies it. Named hooks
|
|
1860
|
+
* (`data-step-index`, `data-active`…) replace positional `:nth-child()` CSS
|
|
1861
|
+
* over Blok's holders, which breaks the moment a child is inserted, removed or
|
|
1862
|
+
* reordered. The holders stay DIRECT children of `host` — core requires that
|
|
1863
|
+
* (hierarchy reparenting and caret navigation compare `holder.parentElement`
|
|
1864
|
+
* by identity), so decoration is attributes, never wrapper elements.
|
|
1865
|
+
* Attributes the callback stops producing are removed on the next pass.
|
|
1866
|
+
*
|
|
1867
|
+
* `childContentAttributes` is the same decoration applied one level IN — on
|
|
1868
|
+
* each child's `[data-blok-element-content]` wrapper instead of its holder —
|
|
1869
|
+
* and is remembered the same way. Core's decoration law blesses both, and a
|
|
1870
|
+
* container needs both: the holder is the child's outer box (rails, indices,
|
|
1871
|
+
* hover states), the content wrapper is where the child's own text box begins,
|
|
1872
|
+
* which is what a numbered rail or a connector line has to align to. Reach for
|
|
1873
|
+
* it instead of walking core's wrapper chain from a holder hook (`[data-step] >
|
|
1874
|
+
* [data-blok-element-content] > …`) — those selectors encode engine DOM in host
|
|
1875
|
+
* CSS and break when that structure changes. A child whose DOM has not
|
|
1876
|
+
* committed yet has no wrapper to write to and is stamped on the next pass.
|
|
1877
|
+
*
|
|
1878
|
+
* Writing on a child's holder is inert by design: core's mutation filter drops
|
|
1879
|
+
* a holder-targeted attribute record for the child block and suppresses it for
|
|
1880
|
+
* the container. The guarantee stops at the holder and its
|
|
1881
|
+
* `[data-blok-element-content]` wrapper — writing AT or BELOW a child's tool
|
|
1882
|
+
* root DOES score as that child's edit.
|
|
1883
|
+
*/
|
|
1884
|
+
mountChildren: (host: HTMLElement, childAttributes?: ChildAttributesFn, childContentAttributes?: ChildAttributesFn) => void;
|
|
1885
|
+
/**
|
|
1886
|
+
* Name the element the +/drag toolbar should vertically center on, from inside
|
|
1887
|
+
* the component: `ctx.setToolbarAnchor(this.head().nativeElement)` in
|
|
1888
|
+
* `ngAfterViewInit`. The Angular counterpart of React's/Vue's
|
|
1889
|
+
* `toolbarAnchorRef` — core's `getToolbarAnchorElement` is otherwise a
|
|
1890
|
+
* `(host, block) => Element` hook resolved OUTSIDE the component, so pointing
|
|
1891
|
+
* at an element the template renders meant inventing a data attribute and
|
|
1892
|
+
* `querySelector`-ing for it from
|
|
1893
|
+
* `CreateAngularBlockSpec.getToolbarAnchorElement`.
|
|
1894
|
+
*
|
|
1895
|
+
* A container block whose own chrome is not editable needs an anchor: with
|
|
1896
|
+
* none, core centers the toolbar on the first `[contenteditable]` under the
|
|
1897
|
+
* host, which for a container is its FIRST CHILD BLOCK — parking the +/drag
|
|
1898
|
+
* handles halfway down, beside content that has a toolbar of its own.
|
|
1899
|
+
*
|
|
1900
|
+
* The element set here outranks the declared hook while it is MOUNTED; once it
|
|
1901
|
+
* detaches (or `null` is passed) the hook takes over again, so the toolbar is
|
|
1902
|
+
* never positioned against a stale node. Never calling it keeps core's default.
|
|
1903
|
+
*/
|
|
1904
|
+
setToolbarAnchor: (element: HTMLElement | null) => void;
|
|
1035
1905
|
}
|
|
1036
1906
|
/** DI token carrying the per-block render context into the authored component. */
|
|
1037
|
-
declare const BLOK_BLOCK_CONTEXT: InjectionToken<AngularBlockRenderContext<unknown>>;
|
|
1038
|
-
|
|
1907
|
+
export declare const BLOK_BLOCK_CONTEXT: InjectionToken<AngularBlockRenderContext<unknown>>;
|
|
1039
1908
|
/**
|
|
1040
1909
|
* DI token carrying the LIVE editor instance (as a signal) into every block
|
|
1041
1910
|
* mounted by `createAngularBlock`. `BlokContentDirective` publishes its own
|
|
@@ -1045,7 +1914,7 @@ declare const BLOK_BLOCK_CONTEXT: InjectionToken<AngularBlockRenderContext<unkno
|
|
|
1045
1914
|
* Provided on the block's ELEMENT injector by the portal registry, so it is
|
|
1046
1915
|
* per-EDITOR: two editors on one page each publish their own instance.
|
|
1047
1916
|
*/
|
|
1048
|
-
declare const BLOK_EDITOR_INSTANCE: InjectionToken<Signal<Blok | null>>;
|
|
1917
|
+
export declare const BLOK_EDITOR_INSTANCE: InjectionToken<Signal<Blok | null>>;
|
|
1049
1918
|
/**
|
|
1050
1919
|
* The live Blok instance the component is mounted inside, as a signal, or a
|
|
1051
1920
|
* signal of null before it exists. Inside a `createAngularBlock` component this
|
|
@@ -1065,7 +1934,5 @@ declare const BLOK_EDITOR_INSTANCE: InjectionToken<Signal<Blok | null>>;
|
|
|
1065
1934
|
* Call it in an injection context (a field initializer or the constructor).
|
|
1066
1935
|
* Outside an editor it returns a signal of null.
|
|
1067
1936
|
*/
|
|
1068
|
-
declare function injectBlokInstance(): Signal<Blok | null>;
|
|
1069
|
-
|
|
1070
|
-
export { BLOK_BLOCK_CONTEXT, BLOK_DEFAULT_CONFIG, BLOK_EDITOR_INSTANCE, BlokContentDirective, BlokEditorComponent, createAngularBlock, injectBlocks, injectBlokInstance, injectBlokReady, provideBlok };
|
|
1071
|
-
export type { AngularBlockMountedContext, AngularBlockRenderContext, BlockNode, BlockToolStatics, BlokAngularConfig, BlokReadyScope, CaretTarget, ChildAttributes, ChildAttributesFn, CreateAngularBlockSpec, InjectBlocksOptions, InjectBlokReadyOptions, InsertPosition, InsertSpec, MoveTarget, PropSchema, PropSchemaEntry, TreeInsertSpec, UseBlocksApi };
|
|
1937
|
+
export declare function injectBlokInstance(): Signal<Blok | null>;
|
|
1938
|
+
export type { AngularBlockMountedContext, AngularBlockRenderContext, BlockNode, BlockToolStatics, BlokAngularConfig, BlokReadyScope, CaretTarget, ChildAttributes, ChildAttributesFn, CreateAngularBlockSpec, InjectBlocksOptions, InjectBlokReadyOptions, InsertPosition, InsertSpec, MoveTarget, PropSchema, PropSchemaEntry, TreeInsertSpec, UseBlocksApi };
|