@bloklabs/angular 1.16.1 → 2.1.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.
@@ -1,7 +1,7 @@
1
1
  import * as i0 from "@angular/core";
2
- import { AfterViewInit, DoCheck, ElementRef, EnvironmentProviders, EventEmitter, InjectionToken, OnDestroy, Signal, Type } from "@angular/core";
2
+ import { AfterViewInit, DoCheck, ElementRef, EnvironmentProviders, EventEmitter, InjectionToken, OnChanges, OnDestroy, Signal, SimpleChanges, Type } from "@angular/core";
3
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";
4
+ import { API, BlockAPI, BlockMutationEvent, BlockOrigin, BlockPosition, BlockRenderedPayload, BlockToolConstructable, BlockToolConstructorOptions, BlockToolData, BlockTuneData, BlocksRenderedPayload, Blok, BlokConfig, EditorWidth, LooseOutputData, MarkdownImportConfig, OutputBlockData, OutputData, ResolvedTheme, ThemeMode, ToolboxConfig } from "@bloklabs/core";
5
5
  /**
6
6
  * Configuration for the Angular adapter. Same as `BlokConfig` but without
7
7
  * `holder` (the adapter owns the host element), plus the reactive `width` prop.
@@ -364,12 +364,6 @@ export declare class BlokEditorComponent implements AfterViewInit, DoCheck, OnDe
364
364
  "blockRendered": "blockRendered";
365
365
  }, never, never, true, never>;
366
366
  }
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'];
373
367
  /**
374
368
  * Escape-hatch directive and lifecycle engine for Blok (mirrors React's
375
369
  * `useBlok` + `BlokContent`). Constructs a Blok instance into its own host
@@ -434,6 +428,29 @@ export declare class BlokContentDirective implements OnDestroy {
434
428
  "ready": "ready";
435
429
  }, never, never, true, never>;
436
430
  }
431
+ /**
432
+ * Places the editor's page title in this element, through `editor.title.mount`.
433
+ * The editor needs `pageTitle` set; this only moves the title.
434
+ * On destroy the title goes back above the first block. Projected content is not rendered.
435
+ *
436
+ * ```html
437
+ * <blok-title [editor]="ed.instance()"></blok-title>
438
+ * <blok-editor #ed="blok" [config]="{ pageTitle: true }"></blok-editor>
439
+ * ```
440
+ */
441
+ export declare class BlokTitleComponent implements OnChanges, OnDestroy {
442
+ private readonly host;
443
+ editor: Blok | null;
444
+ ngOnChanges(changes: SimpleChanges): void;
445
+ ngOnDestroy(): void;
446
+ static ɵfac: i0.ɵɵFactoryDeclaration<BlokTitleComponent, never>;
447
+ static ɵcmp: i0.ɵɵComponentDeclaration<BlokTitleComponent, "blok-title", never, {
448
+ "editor": {
449
+ "alias": "editor";
450
+ "required": false;
451
+ };
452
+ }, {}, never, never, true, never>;
453
+ }
437
454
  /**
438
455
  * DI token holding app-wide Blok defaults (shared tools registry, default theme,
439
456
  * i18n). Merged under per-instance inputs by `BlokEditorComponent`.
@@ -512,6 +529,20 @@ interface InsertSpec {
512
529
  */
513
530
  caret?: CaretTarget;
514
531
  }
532
+ /** Spec for {@link UseBlocksApi.create}. */
533
+ interface CreateSpec {
534
+ type?: string;
535
+ data?: BlockToolData;
536
+ /** `null` is the root. Omitted: the `before`/`after` sibling's parent, or the root. */
537
+ parentId?: string | null;
538
+ /** Defaults to `'end'`. */
539
+ position?: InsertPosition;
540
+ id?: string;
541
+ tunes?: {
542
+ [name: string]: BlockTuneData;
543
+ };
544
+ focus?: boolean;
545
+ }
515
546
  /**
516
547
  * One node of a pre-built nested subtree for {@link UseBlocksApi.insertTree}.
517
548
  *
@@ -618,7 +649,7 @@ interface UseBlocksApi {
618
649
  *
619
650
  * `config` (optional {@link MarkdownImportConfig}) is forwarded to the
620
651
  * converter so custom-tool consumers can map markdown nodes into their tools
621
- * (`toolMap`/`onUnknownNode`), toggle GFM, or add micromark/mdast extensions.
652
+ * (`toolMap`/`onUnknownNode`) or toggle GFM.
622
653
  *
623
654
  * Returns ALL created {@link BlockNode}s in document order — including any the
624
655
  * markdown nested internally (e.g. a table's cell children), not just the
@@ -640,9 +671,12 @@ interface UseBlocksApi {
640
671
  * additive {@link insertMarkdown}). Async: the serializer is lazy-loaded, like
641
672
  * the importer. Markdown cannot express every block, so some structure is
642
673
  * dropped (table `colspan`/`rowspan`, heading columns). Returns `''` for an
643
- * empty document. Pre-ready: resolves to `''`.
674
+ * empty document. Pre-ready: resolves to `''`. `title: true` writes the
675
+ * page title first, as core's does.
644
676
  */
645
- exportMarkdown(): Promise<string>;
677
+ exportMarkdown(options?: {
678
+ title?: boolean;
679
+ }): Promise<string>;
646
680
  move(id: string, target: MoveTarget): void;
647
681
  nest(id: string, parentId: string): void;
648
682
  unnest(id: string): void;
@@ -761,6 +795,14 @@ interface UseBlocksApi {
761
795
  * dep array. Pre-ready: `null`.
762
796
  */
763
797
  insertInsideParent(parentId: string, insertIndex: number, childData?: BlockToolData): BlockNode | null;
798
+ /**
799
+ * Add a block the way a toolbox pick does, for a host button such as "New
800
+ * page" — delegates to core's `blocks.create`. Goes to the end of the root
801
+ * unless `parentId`/`position` say otherwise. Resolves `null` for an unknown
802
+ * tool or a place that does not exist; rejects with the tool's
803
+ * `prepareInsert` error, inserting nothing. Pre-ready: `null`.
804
+ */
805
+ create(spec?: CreateSpec): Promise<BlockNode | null>;
764
806
  /**
765
807
  * Replace the WHOLE document with blocks parsed from saved {@link OutputData}
766
808
  * (the `save()` shape) — delegates to core's `blocks.render`. Unlike
@@ -784,249 +826,6 @@ interface UseBlocksApi {
784
826
  */
785
827
  isSyncingFromYjs(): boolean;
786
828
  }
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;
893
- }
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;
1030
829
  /** One field of a block's prop schema. */
1031
830
  interface PropSchemaEntry {
1032
831
  /** Default value, used when the incoming data omits this key. */
@@ -1040,504 +839,6 @@ interface PropSchemaEntry {
1040
839
  * written as its explicit default, never dropped).
1041
840
  */
1042
841
  type PropSchema = Record<string, PropSchemaEntry>;
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";
1541
842
  /**
1542
843
  * Every STATIC member of core's block-tool contract an Angular block may declare
1543
844
  * for itself — `ownsChildren`, `keepsChildrenOnEnter`, `conversionConfig`,
@@ -1623,6 +924,19 @@ interface CreateAngularBlockSpec<Data = BlockToolData> {
1623
924
  * @param block - this block's per-block API
1624
925
  */
1625
926
  onNavigationEnter?: (event: KeyboardEvent, block: BlockAPI) => boolean;
927
+ /**
928
+ * Core's `isReadOnly` hook: true when this block takes no edits from the
929
+ * user or an agent while the editor stays editable (no delete, move, merge,
930
+ * nesting or undo into it). Asked on each gesture; a throw counts as true.
931
+ * @param block - this block's per-block API
932
+ */
933
+ isReadOnly?: (block: BlockAPI) => boolean;
934
+ /**
935
+ * Core's `isDataReadOnly` hook: true when only this block's own data is
936
+ * frozen and its children stay open. A throw counts as true.
937
+ * @param block - this block's per-block API
938
+ */
939
+ isDataReadOnly?: (block: BlockAPI) => boolean;
1626
940
  /** Optional lifecycle callbacks mapped from Blok's block hooks. */
1627
941
  onRendered?: (block: BlockAPI) => void;
1628
942
  /**
@@ -1676,7 +990,10 @@ interface CreateAngularBlockSpec<Data = BlockToolData> {
1676
990
  */
1677
991
  onCreated?: (block: BlockAPI, context: AngularBlockMountedContext) => void;
1678
992
  onMoved?: (block: BlockAPI) => void;
1679
- onRemoved?: (block: BlockAPI) => void;
993
+ /** `removal.deleted` is true when a local edit deleted the block (see BlockTool.removed). */
994
+ onRemoved?: (block: BlockAPI, removal?: {
995
+ deleted: boolean;
996
+ }) => void;
1680
997
  }
1681
998
  /**
1682
999
  * Author a first-party Angular block. Returns a `BlockToolConstructable`
@@ -1701,9 +1018,13 @@ export declare function createAngularBlock<Data = BlockToolData>(spec: CreateAng
1701
1018
  setReadOnly(state: boolean): void;
1702
1019
  getToolbarAnchorElement(): HTMLElement | undefined;
1703
1020
  onNavigationEnter(event: KeyboardEvent): boolean;
1021
+ isReadOnly(): boolean;
1022
+ isDataReadOnly(): boolean;
1704
1023
  rendered(): void;
1705
1024
  moved(): void;
1706
- removed(): void;
1025
+ removed(removal?: {
1026
+ deleted: boolean;
1027
+ }): void;
1707
1028
  destroy(): void;
1708
1029
  }) & BlockToolStatics & {
1709
1030
  readonly __isBlokAngularBlock: true;
@@ -1935,4 +1256,4 @@ export declare const BLOK_EDITOR_INSTANCE: InjectionToken<Signal<Blok | null>>;
1935
1256
  * Outside an editor it returns a signal of null.
1936
1257
  */
1937
1258
  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 };
1259
+ export type { AngularBlockMountedContext, AngularBlockRenderContext, BlockNode, BlockToolStatics, BlokAngularConfig, BlokReadyScope, CaretTarget, ChildAttributes, ChildAttributesFn, CreateAngularBlockSpec, CreateSpec, InjectBlocksOptions, InjectBlokReadyOptions, InsertPosition, InsertSpec, MoveTarget, PropSchema, PropSchemaEntry, TreeInsertSpec, UseBlocksApi };