@bloklabs/angular 1.15.2 → 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bloklabs-angular.mjs","sources":["../../../../dist/.angular-build/angular/provide-blok.ts","../../../../dist/.angular-build/angular/block-context.ts","../../../../dist/.angular-build/angular/blok-instance.ts","../../../../dist/.angular-build/angular/block-portal-registry.ts","../../../../dist/.angular-build/angular/registry-map.ts","../../../../dist/.angular-build/angular/blok-content.directive.ts","../../../../dist/.angular-build/components/errors/tool-not-found.ts","../../../../dist/.angular-build/components/utils/id-generator.ts","../../../../dist/.angular-build/shared/flatten-tree.ts","../../../../dist/.angular-build/components/utils/blocks-tree.ts","../../../../dist/.angular-build/components/utils/blocks-api.ts","../../../../dist/.angular-build/components/utils/readonly-config.ts","../../../../dist/.angular-build/shared/deep-equal.ts","../../../../dist/.angular-build/shared/output-data.ts","../../../../dist/.angular-build/shared/prop-schema.ts","../../../../dist/.angular-build/components/constants/data-attributes.ts","../../../../dist/.angular-build/components/utils/html.ts","../../../../dist/.angular-build/tools/nested-blocks.ts","../../../../dist/.angular-build/tools/child-decoration.ts","../../../../dist/.angular-build/components/events/BlockChildrenMounted.ts","../../../../dist/.angular-build/angular/blok-editor.component.ts","../../../../dist/.angular-build/angular/createAngularBlock.ts","../../../../dist/.angular-build/angular/useBlocks.ts","../../../../dist/.angular-build/angular/useBlokReady.ts","../../../../dist/.angular-build/bloklabs-angular.ts"],"sourcesContent":["import {\n InjectionToken,\n makeEnvironmentProviders,\n type EnvironmentProviders,\n} from '@angular/core';\nimport type { BlokAngularConfig } from './types';\n\n/**\n * DI token holding app-wide Blok defaults (shared tools registry, default theme,\n * i18n). Merged under per-instance inputs by `BlokEditorComponent`.\n */\nexport const BLOK_DEFAULT_CONFIG = new InjectionToken<Partial<BlokAngularConfig>>(\n 'BLOK_DEFAULT_CONFIG'\n);\n\n/**\n * Standalone provider registering app-wide Blok defaults.\n *\n * @example\n * ```ts\n * bootstrapApplication(AppComponent, {\n * providers: [provideBlok({ theme: 'dark', tools: sharedTools })],\n * });\n * ```\n */\nexport function provideBlok(defaults: Partial<BlokAngularConfig>): EnvironmentProviders {\n return makeEnvironmentProviders([{ provide: BLOK_DEFAULT_CONFIG, useValue: defaults }]);\n}\n","import type { API, BlockAPI } from '@bloklabs/core';\n// packages/angular/src/block-context.ts\nimport { InjectionToken, type Signal } from '@angular/core';\n\n\n/**\n * One child's decoration: attribute name → value. `null`/`undefined` removes the\n * attribute; a boolean or number is stringified (so `false` writes\n * `data-active=\"false\"`, which CSS can select, rather than dropping the hook).\n */\nexport type ChildAttributes = Record<string, string | number | boolean | null | undefined>;\n\n/** The per-child decorator accepted by {@link AngularBlockRenderContext.mountChildren}. */\nexport type ChildAttributesFn = (child: BlockAPI, index: number) => ChildAttributes;\n\n/**\n * Context handed to a `createAngularBlock` component. Delivered via DI (the\n * BLOK_BLOCK_CONTEXT token) rather than @Input, because core constructs the tool\n * outside Angular and the signal-input() form does not compile under the repo's\n * JIT test harness. The ONLY data write path is `commit`.\n */\nexport interface AngularBlockRenderContext<Data> {\n /** Reactive, FROZEN snapshot of the block data. Read `data()`; never mutate. */\n data: Signal<Readonly<Data>>;\n /** The ONLY data write path: merge a partial patch and sync once. */\n commit: (patch: Partial<Data>) => void;\n /** This block's per-block API (id, getChildren, dispatchChange…). */\n block: BlockAPI;\n /**\n * The EDITOR-level API this block belongs to (`api.blocks`, `api.caret`,\n * `api.toolbar`…) — the same object a vanilla tool receives in its\n * constructor. Reach for it when a block has to drive the document around it\n * instead of routing everything through `block.call()` string dispatch.\n *\n * For the reactive, id/parentId-relative view of the tree (and to re-render\n * when your own children change), pair `injectBlocks` with\n * `injectBlokInstance()` instead — the api handle itself is not reactive.\n */\n api: API;\n /**\n * Reactive read-only flag. Read `readOnly()` in the template to disable\n * editing (drop `contenteditable`, hide controls). Toggled IN PLACE by core's\n * read-only switch — the component reacts without a remount, so ephemeral\n * state survives. A block that ignores it stays interactive when the editor is\n * read-only (same contract as a vanilla tool's `setReadOnly`).\n */\n readOnly: Signal<boolean>;\n /**\n * Container blocks only: append this block's real child holders into `host`\n * (a `data-blok-nested` element the author owns). Call it once in\n * `ngAfterViewInit`; the factory re-runs the same mount on every data change\n * so late-added children appear. Angular must NOT manage these child holders.\n *\n * `childAttributes` decorates each child's HOLDER after the holders are\n * mounted, and is REMEMBERED — every later remount re-applies it. Named hooks\n * (`data-step-index`, `data-active`…) replace positional `:nth-child()` CSS\n * over Blok's holders, which breaks the moment a child is inserted, removed or\n * reordered. The holders stay DIRECT children of `host` — core requires that\n * (hierarchy reparenting and caret navigation compare `holder.parentElement`\n * by identity), so decoration is attributes, never wrapper elements.\n * Attributes the callback stops producing are removed on the next pass.\n *\n * `childContentAttributes` is the same decoration applied one level IN — on\n * each child's `[data-blok-element-content]` wrapper instead of its holder —\n * and is remembered the same way. Core's decoration law blesses both, and a\n * container needs both: the holder is the child's outer box (rails, indices,\n * hover states), the content wrapper is where the child's own text box begins,\n * which is what a numbered rail or a connector line has to align to. Reach for\n * it instead of walking core's wrapper chain from a holder hook (`[data-step] >\n * [data-blok-element-content] > …`) — those selectors encode engine DOM in host\n * CSS and break when that structure changes. A child whose DOM has not\n * committed yet has no wrapper to write to and is stamped on the next pass.\n *\n * Writing on a child's holder is inert by design: core's mutation filter drops\n * a holder-targeted attribute record for the child block and suppresses it for\n * the container. The guarantee stops at the holder and its\n * `[data-blok-element-content]` wrapper — writing AT or BELOW a child's tool\n * root DOES score as that child's edit.\n */\n mountChildren: (\n host: HTMLElement,\n childAttributes?: ChildAttributesFn,\n childContentAttributes?: ChildAttributesFn\n ) => void;\n /**\n * Name the element the +/drag toolbar should vertically center on, from inside\n * the component: `ctx.setToolbarAnchor(this.head().nativeElement)` in\n * `ngAfterViewInit`. The Angular counterpart of React's/Vue's\n * `toolbarAnchorRef` — core's `getToolbarAnchorElement` is otherwise a\n * `(host, block) => Element` hook resolved OUTSIDE the component, so pointing\n * at an element the template renders meant inventing a data attribute and\n * `querySelector`-ing for it from\n * `CreateAngularBlockSpec.getToolbarAnchorElement`.\n *\n * A container block whose own chrome is not editable needs an anchor: with\n * none, core centers the toolbar on the first `[contenteditable]` under the\n * host, which for a container is its FIRST CHILD BLOCK — parking the +/drag\n * handles halfway down, beside content that has a toolbar of its own.\n *\n * The element set here outranks the declared hook while it is MOUNTED; once it\n * detaches (or `null` is passed) the hook takes over again, so the toolbar is\n * never positioned against a stale node. Never calling it keeps core's default.\n */\n setToolbarAnchor: (element: HTMLElement | null) => void;\n}\n\n/** DI token carrying the per-block render context into the authored component. */\nexport const BLOK_BLOCK_CONTEXT = new InjectionToken<AngularBlockRenderContext<unknown>>(\n 'BLOK_BLOCK_CONTEXT'\n);\n","import type { Blok } from '@bloklabs/core';\n// packages/angular/src/blok-instance.ts\nimport { inject, InjectionToken, signal, type Signal } from '@angular/core';\n\n\n/**\n * DI token carrying the LIVE editor instance (as a signal) into every block\n * mounted by `createAngularBlock`. `BlokContentDirective` publishes its own\n * `instance` signal through it, so the value is null before the editor is ready\n * and after teardown — matching the React/Vue adapters' pre-ready contract.\n *\n * Provided on the block's ELEMENT injector by the portal registry, so it is\n * per-EDITOR: two editors on one page each publish their own instance.\n */\nexport const BLOK_EDITOR_INSTANCE = new InjectionToken<Signal<Blok | null>>(\n 'BLOK_EDITOR_INSTANCE'\n);\n\n/** Stable \"no editor here\" signal for components mounted outside an editor. */\nconst NO_EDITOR: Signal<Blok | null> = signal(null).asReadonly();\n\n/**\n * The live Blok instance the component is mounted inside, as a signal, or a\n * signal of null before it exists. Inside a `createAngularBlock` component this\n * is the block's OWN editor — so a block can drive the tree it lives in without\n * the host prop-drilling the instance into it:\n *\n * ```ts\n * private readonly editor = injectBlokInstance();\n * private readonly blocks = injectBlocks(this.editor);\n * ```\n *\n * That pairing is also what makes a container block REACTIVE to its own child\n * tree: `injectBlocks` refreshes on the editor's `block changed` event, which\n * core emits for every structural mutation — including children the adapter\n * itself never sees (a pasted paragraph, a Tab-indent from the keyboard).\n *\n * Call it in an injection context (a field initializer or the constructor).\n * Outside an editor it returns a signal of null.\n */\nexport function injectBlokInstance(): Signal<Blok | null> {\n return inject(BLOK_EDITOR_INSTANCE, { optional: true }) ?? NO_EDITOR;\n}\n","import type { Blok } from '@bloklabs/core';\n// packages/angular/src/block-portal-registry.ts\nimport {\n ApplicationRef,\n createComponent,\n EnvironmentInjector,\n ErrorHandler,\n Injector,\n type ComponentRef,\n type Signal,\n type Type,\n} from '@angular/core';\n\n\nimport { BLOK_BLOCK_CONTEXT, type AngularBlockRenderContext } from './block-context';\nimport { BLOK_EDITOR_INSTANCE } from './blok-instance';\n\n/**\n * Tool-config key carrying the editor's portal registry into a\n * `createAngularBlock` tool. The tool is constructed by CORE (outside any Angular\n * injection context), so it cannot `inject()` — the directive injects the\n * editor-scoped registry through each Angular-block tool's `config`, and the tool\n * reads it back from there.\n */\nexport const BLOK_PORTAL_REGISTRY_CONFIG_KEY = '__blokAngularPortalRegistry';\n\n/** One mounted Angular block: the Blok-owned host the component renders into. */\nexport interface BlockPortalEntry {\n hostEl: HTMLElement;\n component: Type<unknown>;\n context: AngularBlockRenderContext<unknown>;\n}\n\n/**\n * Per-editor registry of Angular blocks. Mounts each authored component directly\n * into its core-owned host via `createComponent({ hostElement })` (the Teleport\n * analog) and enrolls it in `ApplicationRef` for change detection. A plain Map —\n * Angular has no reactive-proxy hazard, so no `markRaw` equivalent is needed.\n */\nexport interface BlockPortalRegistry {\n /** Mount (or replace) the component for `id` into `entry.hostEl`. */\n register(id: string, entry: BlockPortalEntry): void;\n /**\n * Detach + destroy the component for `id`. Safe (no-op) when absent.\n *\n * Pass the caller's own `hostEl` to make the teardown OWNERSHIP-CHECKED: the\n * mount is destroyed only when it is still the one that host registered. Core\n * composes a replacement block (which registers under the SAME id) BEFORE it\n * destroys the block it replaces, so a superseded tool's `removed()`/\n * `destroy()` teardown arrives after the live mount already exists — without\n * the check it destroys that live componentRef and clears its host.\n */\n unregister(id: string, hostEl?: HTMLElement): void;\n /** Re-run change detection on the block's component (in-place update). */\n flush(id: string): void;\n /** Detach + destroy every mounted block (editor teardown / recreate). */\n destroyAll(): void;\n}\n\n/**\n * Create a fresh portal registry bound to a live Angular environment. One per\n * editor instance (associated via the registry map). The injectors/appRef are\n * passed in (captured by the directive in an injection context) because the\n * registry itself is built outside one.\n *\n * `editor` is the directive's own instance signal. It is passed at CREATION\n * (before the editor exists) rather than set later precisely because it is a\n * signal: blocks mounted during boot read null and re-read the real instance\n * once it resolves.\n * @param envInjector - the app environment injector (parent of each block's)\n * @param appRef - the ApplicationRef each mounted block view is attached to\n * @param errorHandler - where a throwing author component is reported\n * @param editor - signal of the live Blok instance, published to blocks via\n * {@link BLOK_EDITOR_INSTANCE}; omit for registries with no editor to publish\n */\nexport const createBlockPortalRegistry = (\n envInjector: EnvironmentInjector,\n appRef: ApplicationRef,\n errorHandler: ErrorHandler,\n editor?: Signal<Blok | null>\n): BlockPortalRegistry => {\n const mounted = new Map<string, { ref: ComponentRef<unknown>; injector: Injector }>();\n\n // Change detection runs outside NgZone here; a throwing author component must\n // degrade to a blank holder, not break core's block insertion.\n const safe = (fn: () => void): void => {\n try {\n fn();\n } catch (error) {\n errorHandler.handleError(error);\n }\n };\n\n const teardown = (id: string, ownerHostEl?: HTMLElement): void => {\n const entry = mounted.get(id);\n\n if (entry === undefined) {\n return;\n }\n\n const { ref, injector } = entry;\n // Capture host before deletion so we can clear it below.\n const hostEl = ref.location.nativeElement as HTMLElement;\n\n // A superseded owner may not destroy the mount that replaced it.\n if (ownerHostEl !== undefined && hostEl !== ownerHostEl) {\n return;\n }\n\n mounted.delete(id);\n appRef.detachView(ref.hostView);\n ref.destroy();\n // `Injector.create({ parent })` returns an injector that is NOT torn down by\n // `ref.destroy()`. We must destroy it explicitly to prevent one small injector\n // accumulating per block over a long editor session.\n const destroyable = injector as Injector & { destroy?: () => void };\n destroyable.destroy?.();\n // createComponent({ hostElement }) renders INTO an external div. Angular's\n // destroy() tears down the component instance and CD but does NOT clear the\n // host's DOM children — we must do it explicitly.\n hostEl.replaceChildren();\n };\n\n return {\n register(id: string, entry: BlockPortalEntry): void {\n // Idempotent: replace any prior mount for this id.\n teardown(id);\n\n // The context is provided through an ELEMENT injector (a node injector),\n // so it is destroyed automatically with the component view — no leaked\n // EnvironmentInjector. The shared app envInjector is the parent, so author\n // blocks still see app-level providers (HttpClient, etc.).\n const elementInjector = Injector.create({\n providers: [\n { provide: BLOK_BLOCK_CONTEXT, useValue: entry.context },\n // Per-EDITOR, so two editors on one page each publish their own\n // instance to their own blocks.\n ...(editor === undefined\n ? []\n : [{ provide: BLOK_EDITOR_INSTANCE, useValue: editor }]),\n ],\n parent: envInjector,\n });\n\n safe(() => {\n const ref = createComponent(entry.component, {\n environmentInjector: envInjector,\n elementInjector,\n hostElement: entry.hostEl,\n });\n\n appRef.attachView(ref.hostView);\n mounted.set(id, { ref, injector: elementInjector });\n // createComponent does not auto-run CD; render synchronously into the\n // (still-detached) host before core inserts it into the document.\n ref.changeDetectorRef.detectChanges();\n });\n },\n unregister(id: string, hostEl?: HTMLElement): void {\n teardown(id, hostEl);\n },\n flush(id: string): void {\n const entry = mounted.get(id);\n\n if (entry === undefined) {\n return;\n }\n\n safe(() => entry.ref.changeDetectorRef.detectChanges());\n },\n destroyAll(): void {\n for (const id of Array.from(mounted.keys())) {\n teardown(id);\n }\n },\n };\n};\n","// packages/angular/src/registry-map.ts\nimport type { BlockPortalRegistry } from './block-portal-registry';\n\n/**\n * Associates each live Blok instance with its portal registry. `BlokContentDirective`\n * sets it at creation so consumers (and future composables) can reach an editor's\n * registry. WeakMap → no leak when the editor is destroyed.\n */\nconst registries = new WeakMap<WeakKey, BlockPortalRegistry>();\n\nexport function setRegistry(editor: WeakKey, registry: BlockPortalRegistry): void {\n registries.set(editor, registry);\n}\n\nexport function getRegistry(editor: WeakKey): BlockPortalRegistry | undefined {\n return registries.get(editor);\n}\n\nexport function removeRegistry(editor: WeakKey): void {\n registries.delete(editor);\n}\n","import {\n Directive,\n ElementRef,\n EventEmitter,\n NgZone,\n Output,\n PLATFORM_ID,\n Input,\n ApplicationRef,\n EnvironmentInjector,\n ErrorHandler,\n afterNextRender,\n inject,\n signal,\n type OnDestroy,\n} from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n// Imported via the package's public specifier so ng-packagr externalizes the\n// core as a peer dependency (consumers share a single Blok instance + CSS).\nimport { Blok as BlokRuntime, type Blok } from '@bloklabs/core';\nimport { BLOK_DEFAULT_CONFIG } from './provide-blok';\nimport type { BlokAngularConfig } from './types';\nimport {\n BLOK_PORTAL_REGISTRY_CONFIG_KEY,\n createBlockPortalRegistry,\n type BlockPortalRegistry,\n} from './block-portal-registry';\nimport { removeRegistry, setRegistry } from './registry-map';\n\n/**\n * Escape-hatch directive and lifecycle engine for Blok (mirrors React's\n * `useBlok` + `BlokContent`). Constructs a Blok instance into its own host\n * element and tears it down on destroy.\n *\n * The editor renders directly into the directive's host element — so the host\n * IS the holder. This sidesteps the fact that Blok core exposes no public\n * `holder` accessor: the adapter never has to read it back, it owns it.\n *\n * `BlokEditorComponent` applies this directive to its internal `<div>` and reads\n * the instance back; consumers can also use it directly for full control:\n * `<div blokContent [config]=\"cfg\" (ready)=\"onReady($event)\"></div>`.\n *\n * Implementation note: classic `@Input()`/`@Output()` are used (not signal\n * `input()`/`output()`) because the repo's Vitest+Analog harness compiles the\n * adapter via JIT, which does not register signal-based members. `instance`\n * remains a plain `signal` (runtime API, JIT-safe) for reactive consumption.\n */\n@Directive({\n selector: '[blokContent]',\n standalone: true,\n})\nexport class BlokContentDirective implements OnDestroy {\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly ngZone = inject(NgZone);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n /**\n * App-wide defaults from `provideBlok()`, merged UNDER the bound `[config]` so\n * the escape-hatch path honors them just like `<blok-editor>` (which also\n * merges, idempotently). Mirrors React's `useBlok` merging context defaults.\n */\n private readonly defaults = inject(BLOK_DEFAULT_CONFIG, { optional: true }) ?? {};\n // Captured in the injection context (field initializers) so the registry can\n // mount author components via createComponent — core constructs tools outside\n // Angular DI and cannot inject these itself.\n private readonly envInjector = inject(EnvironmentInjector);\n private readonly appRef = inject(ApplicationRef);\n private readonly errorHandler = inject(ErrorHandler);\n\n /** Construction-time Blok config (everything except `holder`, which the directive owns). */\n @Input() config: Partial<BlokAngularConfig> = {};\n\n /** Changing this input's identity (after the first build) destroys + recreates the editor. */\n @Input() set recreateKey(value: unknown) {\n const changed = this.built && value !== this.currentKey;\n this.currentKey = value;\n\n if (changed) {\n this.current?.destroy();\n this.build();\n }\n }\n\n /** Emits the live Blok instance once it is ready, after `instance` is populated. */\n @Output() readonly ready = new EventEmitter<Blok>();\n\n /** The live Blok instance, or null before `isReady` resolves / after destroy. */\n readonly instance = signal<Blok | null>(null);\n\n /** The editor created by the most recent construction; used as the staleness key. */\n private current: Blok | null = null;\n private destroyed = false;\n private built = false;\n private currentKey: unknown;\n /** The portal registry for the current editor (Angular-block mounting). */\n private registry: BlockPortalRegistry | undefined;\n\n constructor() {\n // afterNextRender is browser-only (skipped during SSR) and runs after the\n // host element exists and inputs are bound.\n afterNextRender(() => {\n // afterNextRender is browser-only by contract, but guard explicitly so the\n // editor is never constructed during SSR / on a non-browser platform.\n if (this.destroyed || !this.isBrowser) {\n return;\n }\n\n this.build();\n this.built = true;\n });\n }\n\n /** Construct a Blok into the host element and publish it once ready. */\n private build(): void {\n this.destroyed = false;\n this.instance.set(null);\n\n // Tear down any registry from a superseded editor (recreate path) before\n // building a new one.\n this.registry?.destroyAll();\n\n // Merge provideBlok defaults under the bound config (instance wins; tools\n // registries compose across both layers rather than replacing).\n const merged: Partial<BlokAngularConfig> = { ...this.defaults, ...this.config };\n\n if (this.defaults.tools !== undefined || this.config.tools !== undefined) {\n merged.tools = { ...this.defaults.tools, ...this.config.tools };\n }\n\n // Create the editor-scoped portal registry and thread it into every\n // Angular-block tool's config (vanilla tools pass through untouched).\n // `this.instance` is handed over at creation: it is a SIGNAL, so blocks\n // mounted during boot read null and re-read the real editor once isReady\n // resolves — no ordering problem, and `injectBlokInstance()` inside a block\n // component tracks the swap.\n const registry = createBlockPortalRegistry(\n this.envInjector,\n this.appRef,\n this.errorHandler,\n this.instance\n );\n\n this.registry = registry;\n merged.tools = injectPortalRegistry(merged.tools, registry);\n\n // Construct outside Angular's zone so the editor's internal DOM churn never\n // schedules change detection.\n const blok = this.ngZone.runOutsideAngular(\n () =>\n new BlokRuntime({\n ...merged,\n holder: this.host.nativeElement,\n }) as unknown as Blok\n );\n\n this.current = blok;\n setRegistry(blok, registry);\n\n void blok.isReady.then(() =>\n this.ngZone.run(() => {\n // Guard on the constructor-returned reference (not isReady's resolved\n // value): a superseded or torn-down editor must not publish itself.\n if (this.current !== blok || this.destroyed) {\n return;\n }\n\n this.instance.set(blok); // assign FIRST…\n this.ready.emit(blok); // …THEN emit, so consumers see a populated instance.\n })\n );\n }\n\n ngOnDestroy(): void {\n this.destroyed = true;\n this.registry?.destroyAll();\n\n if (this.current !== null) {\n removeRegistry(this.current);\n }\n\n this.current?.destroy();\n this.current = null;\n this.registry = undefined;\n this.instance.set(null);\n }\n}\n\n/**\n * Return a NEW tools map (never mutate the consumer's config) where each\n * Angular-block tool carries the portal registry under\n * BLOK_PORTAL_REGISTRY_CONFIG_KEY in its `config`. Vanilla tools are returned\n * unchanged. Handles both entry shapes: a bare constructor and `{ class, config }`.\n */\nfunction injectPortalRegistry(\n tools: BlokAngularConfig['tools'],\n registry: BlockPortalRegistry\n): BlokAngularConfig['tools'] {\n if (tools === undefined) {\n return tools;\n }\n\n const result: Record<string, unknown> = {};\n\n for (const [name, entry] of Object.entries(tools)) {\n const asObject = entry as { class?: unknown; config?: Record<string, unknown> } | undefined;\n const toolClass = (typeof entry === 'function' ? entry : asObject?.class) as\n | { __isBlokAngularBlock?: boolean }\n | undefined;\n\n if (toolClass?.__isBlokAngularBlock === true) {\n const base = typeof entry === 'function' ? { class: entry } : { ...asObject };\n\n result[name] = {\n ...base,\n config: { ...(base.config ?? {}), [BLOK_PORTAL_REGISTRY_CONFIG_KEY]: registry },\n };\n } else {\n result[name] = entry;\n }\n }\n\n return result as BlokAngularConfig['tools'];\n}\n","/**\n * Thrown when a block tool cannot be resolved during a creation/conversion\n * operation (insert, insertMany/composeBlock, composeBlockData, convert).\n *\n * A typed error lets adapters (React/Vue/Angular useBlocks) distinguish a\n * genuinely-unknown tool — an EXPECTED, recoverable outcome they surface as a\n * `null`/`[]` no-op — from a real bug, WITHOUT brittle `message.includes('not\n * found')` substring matching (which both mis-catches unrelated errors whose\n * message happens to contain \"not found\" and breaks under message localization).\n */\nexport class ToolNotFoundError extends Error {\n /**\n * @param toolName - the tool type that could not be resolved\n * @param message - optional override; defaults to a descriptive message\n */\n constructor(public readonly toolName: string, message?: string) {\n super(message ?? `Block Tool «${toolName}» not found.`);\n this.name = 'ToolNotFoundError';\n }\n}\n","/**\n * ID generation utilities\n */\n\n// nanoid replaced with inline crypto implementation for the Angular adapter bundle.\nconst _ID_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-';\nconst _nanoid = (n: number): string => {\n const buf = crypto.getRandomValues(new Uint8Array(n));\n return Array.from(buf, (b) => _ID_CHARS[b % 64]).join('');\n};\nconst nanoid = _nanoid;\n\n/**\n * Constants for ID generation\n */\nconst ID_RANDOM_MULTIPLIER = 100_000_000; // 1e8\nconst HEXADECIMAL_RADIX = 16;\n\n/**\n * Create a block id\n * @returns unique block ID\n */\nexport const generateBlockId = (): string => {\n const idLen = 10;\n\n return nanoid(idLen);\n};\n\n/**\n * Nanoid-compatible block ID pattern: exactly 10 URL-safe characters (A-Z, a-z, 0-9, _, -)\n */\nconst BLOCK_ID_PATTERN = /^[A-Za-z0-9_-]{10}$/;\n\n/**\n * Returns true if the given string is a valid block ID (nanoid format).\n * @param id - string to check\n */\nexport const isValidBlockId = (id: string): boolean => BLOCK_ID_PATTERN.test(id);\n\n/**\n * Returns random generated identifier\n * @param prefix - identifier prefix\n * @returns unique identifier with prefix\n */\nexport const generateId = (prefix = ''): string => {\n return `${prefix}${(Math.floor(Math.random() * ID_RANDOM_MULTIPLIER)).toString(HEXADECIMAL_RADIX)}`;\n};\n","import type { OutputBlockData, BlockId, BlockRunSpec, BlockTreeNode, BlockTreeSpec, FlattenTreeOptions } from '@bloklabs/core';\nimport { generateBlockId } from '../components/utils/id-generator';\n\n/** A flattened block with its `id` resolved (generated when the spec omitted one). */\ntype FlattenedBlock = OutputBlockData & { id: BlockId };\n\n/**\n * Whether a spec node is a pre-flat run (`{ blocks: [...] }`) rather than a\n * tree node. Keyed on the `blocks` array, the only field the two shapes cannot\n * share.\n * @param node - spec node to classify\n */\nconst isRunSpec = (node: BlockTreeNode): node is BlockRunSpec => {\n return Array.isArray((node as BlockRunSpec).blocks);\n};\n\n/**\n * Wire-tolerant id read: `null` and `''` mean \"absent\", as everywhere else a\n * loaded document is normalized.\n * @param id - id as it arrived on a saved block\n */\nconst nonEmptyId = (id: string | null | undefined): string | undefined => {\n return typeof id === 'string' && id !== '' ? id : undefined;\n};\n\n/**\n * Reject an already-flat block passed where a TREE node is expected. A spec\n * node has no `parent`/`content` fields, so such a block would be flattened\n * with its links silently DROPPED — the structure it described is gone and\n * nothing reports it. Pre-flat blocks belong in a run node instead.\n * @param node - tree node about to be flattened\n * @throws if the node carries link information a tree node cannot express\n */\nconst assertNotPreFlat = (node: BlockTreeSpec): void => {\n const asFlat = node as OutputBlockData;\n const carriesParent = typeof asFlat.parent === 'string' && asFlat.parent !== '';\n const carriesContent = Array.isArray(asFlat.content) && asFlat.content.length > 0;\n\n if (carriesParent || carriesContent) {\n throw new Error(\n `flattenTree: block \"${node.id ?? '(no id)'}\" carries \\`parent\\`/\\`content\\` links, which a tree node cannot express — pass pre-flat blocks as a run node: { blocks: [...] }.`\n );\n }\n};\n\n/**\n * Flatten a hierarchical block spec (nodes with `children`) into the flat DFS\n * pre-order `OutputBlockData[]` Blok stores, wiring every node's `parent` and\n * `content` id links.\n *\n * This is the pure counterpart of the live `insertTree` mutation: the same DFS,\n * without an editor. Use it to seed nested content — columns, tables, a whole\n * document — without hand-authoring `parent`/`content` arrays:\n *\n * @example\n * new Blok({\n * data: {\n * blocks: flattenTree([\n * { type: 'column_list', children: [\n * { type: 'column', children: [{ type: 'paragraph', data: { text: 'L' } }] },\n * { type: 'column', children: [{ type: 'paragraph', data: { text: 'R' } }] },\n * ] },\n * ]),\n * },\n * });\n *\n * Content that is not tree-shaped to begin with — an already-flat saved\n * document a migration is splicing into a page — goes in as a RUN node,\n * `{ blocks: [...] }`, at the root or as a child. A run is spliced verbatim:\n * ids, `data`, `tunes` and existing `parent`/`content` links are kept, and only\n * the blocks it left un-parented are re-parented onto the enclosing node.\n *\n * @example\n * flattenTree({ type: 'column', children: [{ blocks: saved.blocks }] });\n *\n * @param spec - a single root node or an array of root nodes; each is either a\n * tree node or a pre-flat run.\n * @param options - `parentId` sets the `parent` of the root node(s);\n * `generateId` overrides id generation for nodes that omit an `id` (default:\n * Blok's nanoid scheme).\n * @returns DFS pre-order blocks with `parent`/`content` wired. Leaves omit the\n * empty `content` array, matching the documented `OutputBlockData` shape.\n * @throws if an explicit `id` is reused within the spec — a duplicate id would\n * corrupt every id-keyed lookup, so it is surfaced loudly rather than encoded\n * — or if a TREE node carries `parent`/`content` links, which it cannot\n * express (that is a pre-flat block; wrap it in a run node).\n */\nexport function flattenTree(\n spec: BlockTreeNode | BlockTreeNode[],\n options: FlattenTreeOptions = {}\n): FlattenedBlock[] {\n const generateId = options.generateId ?? generateBlockId;\n const rootParent = options.parentId ?? undefined;\n\n const flat: FlattenedBlock[] = [];\n const usedIds = new Set<string>();\n\n /**\n * Resolve a node's id and reserve it. A duplicate would corrupt every\n * id-keyed lookup, so it is surfaced loudly rather than encoded.\n * @param explicitId - id the spec carried, if any\n */\n const claimId = (explicitId: string | undefined): string => {\n const id = explicitId ?? generateId();\n\n if (usedIds.has(id)) {\n throw new Error(`flattenTree: duplicate block id \"${id}\" — every block id must be unique.`);\n }\n usedIds.add(id);\n\n return id;\n };\n\n /**\n * Splice a pre-flat run in verbatim: every block keeps its id, `data`,\n * `tunes` and its existing `parent`/`content` links, and only the blocks the\n * run left un-parented are re-parented onto the enclosing node. Mirrors\n * `useBlocks.insertMarkdown`, which nests a converted run the same way.\n * @param run - the run node\n * @param parent - id of the node the run is spliced into (undefined at root)\n * @returns ids of the run's top-level blocks, in run order\n */\n const visitRun = (run: BlockRunSpec, parent: string | undefined): string[] => {\n const rootIds: string[] = [];\n\n for (const block of run.blocks) {\n const { parent: incomingParent, id: incomingId, content: incomingContent, data, ...rest } = block;\n const id = claimId(nonEmptyId(incomingId));\n const incomingParentId = nonEmptyId(incomingParent);\n const isRunRoot = incomingParentId === undefined;\n const resolvedParent = isRunRoot ? parent : incomingParentId;\n\n flat.push({\n ...rest,\n id,\n data: data ?? {},\n // `null`/`[]` content means \"no children\" — omitted, like a tree leaf.\n ...(Array.isArray(incomingContent) && incomingContent.length > 0 ? { content: incomingContent } : {}),\n ...(resolvedParent !== undefined ? { parent: resolvedParent } : {}),\n });\n\n if (isRunRoot) {\n rootIds.push(id);\n }\n }\n\n return rootIds;\n };\n\n // Pre-order DFS: push self FIRST, then recurse each child, so the flat array\n // is DFS-contiguous. `content` is filled as each child is visited and returns\n // its id; it is omitted for leaves.\n const visit = (node: BlockTreeSpec, parent: string | undefined): string => {\n assertNotPreFlat(node);\n\n const id = claimId(node.id);\n\n const childIds: string[] = [];\n const flatNode = {\n id,\n // `type` is OMITTED (not present-with-undefined) when absent so core's\n // `type || defaultBlock` fallback resolves the default block cleanly.\n ...(node.type !== undefined ? { type: node.type } : {}),\n data: node.data ?? {},\n ...(node.tunes !== undefined ? { tunes: node.tunes } : {}),\n ...(parent !== undefined ? { parent } : {}),\n } as FlattenedBlock;\n\n flat.push(flatNode);\n\n for (const child of node.children ?? []) {\n childIds.push(...(isRunSpec(child) ? visitRun(child, id) : [visit(child, id)]));\n }\n\n // Only wire `content` when there are children — leaves stay clean.\n if (childIds.length > 0) {\n flatNode.content = childIds;\n }\n\n return id;\n };\n\n const roots = Array.isArray(spec) ? spec : [spec];\n\n for (const root of roots) {\n if (isRunSpec(root)) {\n visitRun(root, rootParent);\n } else {\n visit(root, rootParent);\n }\n }\n\n return flat;\n}\n","import type { BlockToolData, BlockTuneData, OutputBlockData, OutputData, MarkdownImportConfig } from '@bloklabs/core';\n\n/**\n * Where to place the caret within a block. `position` selects the input\n * (`'start'`/`'end'`/`'default'`) and `offset` is the character offset within it\n * — the same shape core's `caret.setToBlock` accepts.\n */\nexport interface CaretTarget {\n position?: 'start' | 'end' | 'default';\n offset?: number;\n}\n\n/**\n * A plain, serializable view of one block in the tree.\n *\n * Snapshot-volatile: every read allocates a fresh `BlockNode`, and `contentIds`\n * is DERIVED per read from the children that currently name this block as parent\n * (it is not a stored field). Read a node in render and re-read after a change —\n * don't stash one in a `useMemo`/`useEffect` dependency array expecting stable\n * identity; depend on the `id` instead.\n */\nexport interface BlockNode {\n id: string;\n type: string;\n parentId: string | null;\n contentIds: readonly string[];\n}\n\n/** Where to place a block among its siblings. */\nexport type InsertPosition = 'start' | 'end' | { before: string } | { after: string };\n\nexport interface InsertSpec {\n type?: string;\n data?: BlockToolData;\n parentId?: string | null;\n position?: InsertPosition;\n /**\n * Move the caret into the new block. Defaults to `false`: a programmatic\n * insert from React must not steal focus from wherever the user is typing.\n * Set `true` for an explicit \"add a block and start editing it\" flow.\n */\n focus?: boolean;\n /**\n * Replace the block at the resolved slot instead of inserting a new one — a\n * programmatic \"turn into\". Combine with a `position` that targets the block\n * to replace, e.g. `{ position: { before: id }, replace: true }`.\n */\n replace?: boolean;\n /**\n * Explicit id for the new block (generated when omitted). Passing a stable id\n * makes the insert idempotent: if a block with this id already exists the\n * existing node is returned and nothing is inserted (\"insert if absent\"),\n * so an effect that re-runs won't create duplicates.\n */\n id?: string;\n /** Block tune data to apply at creation, keyed by tune name. */\n tunes?: { [name: string]: BlockTuneData };\n /**\n * Place the caret inside the newly-created block at a specific position/offset\n * (e.g. `{ offset: 3 }`). Implies focus. Applied ONLY when a block is actually\n * created — an insert-if-absent hit (existing id) does not move the caret.\n * Use this instead of the boolean `focus` when you need a specific offset.\n */\n caret?: CaretTarget;\n}\n\n/**\n * One node of a pre-built nested subtree for {@link UseBlocksApi.insertTree}.\n *\n * Each node maps to one block; `children` are inserted nested under it (their\n * `parentId` set to this node's id) in array order, recursively. Placement\n * options (`parentId`/`position`) are ROOT-ONLY — they position the whole\n * subtree among existing blocks and are ignored on nested children, whose parent\n * is always their enclosing node.\n */\nexport interface TreeInsertSpec {\n type?: string;\n data?: BlockToolData;\n tunes?: { [name: string]: BlockTuneData };\n /**\n * Explicit id for this node (generated when omitted). Unlike `insert`, this is\n * NOT insert-if-absent: a tree insert always creates fresh blocks. A colliding\n * id — one that already exists in the document, or is reused by another node\n * in the same spec — is REJECTED up front: nothing is inserted and `insertTree`\n * returns `null` (a duplicate id would corrupt every id-keyed lookup).\n */\n id?: string;\n /** Direct children, inserted nested under this node, in array order. */\n children?: TreeInsertSpec[];\n /** Root-only: where to place the whole subtree. Ignored on nested children. */\n parentId?: string | null;\n /** Root-only: slot among siblings of `parentId`. Ignored on nested children. */\n position?: InsertPosition;\n}\n\n/**\n * Where to move an existing block.\n *\n * `before`/`after` are POSITION targets, not parent assignments: the block is\n * relocated to that flat slot and — because Blok keeps the flat array as the\n * canonical document order — ADOPTS the parent of wherever it lands. Moving a\n * nested block to `{ after: someRootBlock }` therefore unnests it to root, and\n * moving a root block in among a container's children nests it. Use\n * `nest`/`unnest` when you want to change the parent without choosing a sibling\n * slot. `toIndex` is an absolute flat index (clamped into range).\n */\nexport type MoveTarget = { before: string } | { after: string } | { toIndex: number };\n\nexport interface UseBlocksApi {\n getById(id: string): BlockNode | null;\n getChildren(parentId: string | null): BlockNode[];\n /**\n * Insert one block; returns the created node or null when rejected (unknown\n * tool type, dangling `parentId`, or a `replace` whose target is missing). An\n * explicit `id` that already exists is insert-if-absent (returns the existing\n * node, creates nothing). Atomic — one undo step. The returned node is\n * {@link BlockNode}-volatile; read it now, don't put it in a dep array.\n */\n insert(spec?: InsertSpec): BlockNode | null;\n /**\n * Insert several blocks atomically, in array order, as ONE undo step. Each\n * spec is a full {@link InsertSpec} (own type/data/parentId/position), routed\n * through the same single-`insert` path, so per-spec parent assertion and\n * positioning still apply. Specs that fail to insert (e.g. a dangling\n * parentId, or a replace whose target is missing) are dropped; the returned\n * array holds only the successfully created nodes. An empty input is a no-op\n * (returns `[]`, opens no transaction). Like `insert`, the returned nodes are\n * fresh-snapshot volatile — read them now, don't stash them in dep arrays.\n */\n insertMany(specs: InsertSpec[]): BlockNode[];\n /**\n * Insert a pre-built NESTED subtree in ONE atomic operation (one undo step).\n * Each {@link TreeInsertSpec} node becomes a block; its `children` are inserted\n * nested under it (recursively, in array order) so the whole hierarchy lands in\n * a single call — no follow-up `nest` round-trips. Delegates to core's\n * tree-aware `blocks.insertMany`, which composes the flat DFS pre-order array\n * honoring each node's `parent`/`content` links.\n *\n * Placement is root-only: the root node's `parentId`/`position` position the\n * whole subtree among existing blocks (default: appended at the document end);\n * nested children ignore those fields (their parent is their enclosing node). A\n * dangling root `parentId` is rejected — nothing is inserted and `null` is\n * returned (mirrors {@link insert}). Returns the root {@link BlockNode}, which\n * is fresh-snapshot volatile — read it now, don't stash it in a dep array.\n */\n insertTree(spec: TreeInsertSpec): BlockNode | null;\n /**\n * Convert a Markdown string to blocks and insert them ADDITIVELY at a\n * position, WITHOUT clearing the document (unlike core's `importMarkdown` /\n * `renderFromHTML`, which replace the whole document). This is the React\n * \"paste markdown → blocks appear\" path.\n *\n * Async: the markdown converter is lazy-loaded (kept out of the main bundle),\n * so this is the ONE async creator in the API — `await` the returned promise.\n * The whole batch is inserted as a single atomic undo step.\n *\n * `position` (default `'end'`) places the converted run among `parentId`'s\n * children (or root siblings when `parentId` is omitted/null), reusing the\n * same `start`/`end`/`before`/`after` semantics as {@link insert}.\n *\n * `parentId` (default `null` = root) nests the import: every TOP-LEVEL\n * converted block (one the converter left un-parented) is reparented under\n * `parentId`, while blocks the markdown nested internally (e.g. table-cell\n * children) keep their intra-import parent. A dangling `parentId` is a no-op\n * (returns `[]`, opens no transaction), matching {@link insert}.\n *\n * `config` (optional {@link MarkdownImportConfig}) is forwarded to the\n * converter so custom-tool consumers can map markdown nodes into their tools\n * (`toolMap`/`onUnknownNode`), toggle GFM, or add micromark/mdast extensions.\n *\n * Returns ALL created {@link BlockNode}s in document order — including any the\n * markdown nested internally (e.g. a table's cell children), not just the\n * top-level run (this differs from {@link insertTree}, which returns only the\n * root). Empty or whitespace-only markdown, a dangling `parentId` (checked\n * again after the async convert, so a parent removed mid-flight also no-ops),\n * and a converter failure (chunk-load or parse error, swallowed) all return\n * `[]` and open no transaction. The nodes are fresh-snapshot volatile — read\n * them now, don't stash them in dep arrays.\n */\n insertMarkdown(\n markdown: string,\n options?: { parentId?: string | null; position?: InsertPosition; config?: MarkdownImportConfig }\n ): Promise<BlockNode[]>;\n /**\n * Serialize the WHOLE document to a Markdown string — the outbound twin of\n * core's `blocks.exportMarkdown` (and the read-side counterpart of the\n * additive {@link insertMarkdown}). Async: the serializer is lazy-loaded, like\n * the importer. Markdown cannot express every block, so some structure is\n * dropped (table `colspan`/`rowspan`, heading columns). Returns `''` for an\n * empty document. Pre-ready: resolves to `''`.\n */\n exportMarkdown(): Promise<string>;\n move(id: string, target: MoveTarget): void;\n nest(id: string, parentId: string): void;\n unnest(id: string): void;\n remove(id: string): void;\n /**\n * Update a block's data and/or tunes by id. Delegates to core's async\n * `blocks.update`, which forms its OWN undo step — the call is NOT wrapped in\n * `transact` (that would close the group before the async write lands). An\n * unknown id is a silent no-op; a rejected update is swallowed so it can't\n * surface as an unhandled rejection. Reads refresh reactively once core emits\n * 'block changed'. Returns `void`.\n */\n update(id: string, data?: BlockToolData, tunes?: { [name: string]: BlockTuneData }): void;\n /**\n * Convert a block to another type (\"turn into\") by id. Delegates to core's\n * async `blocks.convert`; both tools must provide a `conversionConfig` or core\n * rejects — that rejection (and any other) is swallowed so a non-convertible\n * block is a graceful no-op rather than an unhandled rejection. An unknown id\n * is a silent no-op. Not wrapped in `transact` (core owns its history step).\n * Returns `void`.\n */\n convert(\n id: string,\n newType: string,\n dataOverrides?: BlockToolData,\n options?: { caret?: CaretTarget }\n ): void;\n transact(fn: () => void): void;\n /**\n * Run `fn` as one atomic operation that is NOT captured in the undo history —\n * the React-surface counterpart of core's `transactWithoutCapture`. Use for\n * silent auto-repair/normalization that a user's CMD+Z should never step\n * through. Mutations inside still emit reactively. Pre-ready it just runs `fn`.\n */\n transactWithoutCapture(fn: () => void): void;\n /**\n * The current block count. Reactive (re-reads on 'block changed'). Pre-ready: 0.\n */\n getBlocksCount(): number;\n /**\n * The flat index of the block holding the caret, or -1 when none. Pre-ready: -1.\n */\n getCurrentBlockIndex(): number;\n /** The block at a flat index as a snapshot {@link BlockNode}, or null. */\n getBlockByIndex(index: number): BlockNode | null;\n /**\n * The absolute flat index of a block by id, or null when unknown. The\n * counterpart to {@link getBlockByIndex} — use it to target an off-caret\n * {@link splitBlock} (whose `insertIndex` is absolute) without the ref. Unknown\n * ids return null silently (no console warn). Pre-ready: null.\n */\n getBlockIndex(id: string): number | null;\n /**\n * Read a block's current `data` and `tunes` by id WITHOUT mutating anything —\n * the synchronous last-extracted view (the same snapshot clipboard ops use).\n * Makes a client-side duplicate composable from the hook alone: read a node,\n * then `insert({ type, data, tunes, position })`, no ref escape hatch. Unknown\n * id returns null. Pre-ready: null.\n */\n getBlockData(id: string): { data: BlockToolData; tunes: { [name: string]: BlockTuneData } } | null;\n /**\n * The block whose holder contains/equals `element`, as a snapshot\n * {@link BlockNode}, or null. Useful for mapping a DOM event target back to a\n * block.\n */\n getBlockByElement(element: HTMLElement): BlockNode | null;\n /**\n * Read a tool's default empty data WITHOUT inserting anything — delegates to\n * core's `composeBlockData`. Async (a tool's data may be composed lazily).\n * Rejects (via core) for an unknown tool. Pre-ready: resolves to `{}`.\n */\n composeBlockData(toolName: string): Promise<BlockToolData>;\n /**\n * Replace the WHOLE document with blocks parsed from an HTML string —\n * delegates to core's `renderFromHTML`. Unlike {@link insertMarkdown} (which is\n * additive), this CLEARS existing content first, so it's a document-load\n * primitive, not an insert. Async. Pre-ready: resolves immediately (no-op).\n */\n renderFromHTML(html: string): Promise<void>;\n /**\n * Insert a flat array of already-serialized {@link OutputBlockData} (the\n * `save()` shape) directly, honoring each block's `parent`/`content` links —\n * the raw counterpart of core's `blocks.insertMany`. Use to re-insert a saved\n * document fragment without reshaping it into {@link TreeInsertSpec}. One\n * atomic undo step. Returns the created nodes; pre-ready: `[]` (no insert).\n */\n insertOutputData(blocks: OutputBlockData[], options?: { index?: number }): BlockNode[];\n /**\n * Atomically split a block: update `currentBlockId` with `currentBlockData`\n * and insert a new `newBlockType` block at `insertIndex`, as ONE undo step.\n * Delegates to core's `splitBlock`. Returns the new node, or null pre-ready /\n * on an unknown id.\n */\n splitBlock(\n currentBlockId: string,\n currentBlockData: Partial<BlockToolData>,\n newBlockType: string,\n newBlockData: BlockToolData,\n insertIndex: number\n ): BlockNode | null;\n /**\n * Insert a single child block under `parentId` at flat `insertIndex`, atomically\n * (block creation AND parent assignment in ONE undo step) — delegates to core's\n * `blocks.insertInsideParent`. This is the atomic nested-child creator: prefer it\n * over `insert()` + `nest()`, which is TWO undo steps. A dangling `parentId` is a\n * no-op returning `null` (mirrors {@link insert}); an unknown child tool returns\n * `null`. `childData` defaults to an empty paragraph. Returns the created\n * {@link BlockNode}, fresh-snapshot volatile — read it now, don't stash it in a\n * dep array. Pre-ready: `null`.\n */\n insertInsideParent(parentId: string, insertIndex: number, childData?: BlockToolData): BlockNode | null;\n /**\n * Replace the WHOLE document with blocks parsed from saved {@link OutputData}\n * (the `save()` shape) — delegates to core's `blocks.render`. Unlike\n * {@link insertOutputData}/{@link insertMarkdown} (which are ADDITIVE), this\n * CLEARS existing content first: a document-LOAD primitive, not an insert. The\n * HTML counterpart is {@link renderFromHTML}. Async. Pre-ready: resolves\n * immediately (no-op).\n */\n render(data: OutputData): Promise<void>;\n /**\n * Remove EVERY block from the document — delegates to core's `blocks.clear`. A\n * document-reset primitive (pairs with {@link render}). Async. Pre-ready:\n * resolves immediately (no-op).\n */\n clear(): Promise<void>;\n /**\n * Whether a Yjs sync (undo/redo) is currently in progress — the React mirror of\n * core's `blocks.isSyncingFromYjs`. A METHOD (not a property) so it reads the\n * LIVE flag at call time even though the api handle is memoized. Use it to skip\n * cleanup that would fight Yjs state during an undo/redo. Pre-ready: `false`.\n */\n isSyncingFromYjs(): boolean;\n}\n\n/** The minimal slice of editor.blocks that the snapshot helpers read. */\nexport interface BlocksReader {\n getBlocksCount(): number;\n getBlockByIndex(index: number): { id: string; name: string; parentId: string | null } | undefined;\n}\n\n/**\n * Enumerate the editor's blocks once into BlockNode records, in flat order,\n * deriving each node's contentIds from the children that name it as parent.\n */\nexport const snapshotNodes = (reader: BlocksReader): BlockNode[] => {\n const count = reader.getBlocksCount();\n const flat = Array.from({ length: count }, (_, i) => reader.getBlockByIndex(i))\n .filter((b): b is { id: string; name: string; parentId: string | null } => b !== undefined)\n .map((b) => ({ id: b.id, type: b.name, parentId: b.parentId }));\n\n const childrenByParent = new Map<string, string[]>();\n\n for (const b of flat) {\n if (b.parentId === null) {\n continue;\n }\n const bucket = childrenByParent.get(b.parentId) ?? [];\n\n bucket.push(b.id);\n childrenByParent.set(b.parentId, bucket);\n }\n\n return flat.map((b) => ({\n id: b.id,\n type: b.type,\n parentId: b.parentId,\n contentIds: childrenByParent.get(b.id) ?? [],\n }));\n};\n\n/** BlocksReader plus id→flat-index lookup. */\nexport interface IndexReader extends BlocksReader {\n getBlockIndex(id: string): number | undefined;\n}\n\n/** Flat indices of a parent's direct children, ascending. Empty if none. */\nconst childFlatIndices = (reader: IndexReader, parentId: string): number[] => {\n const count = reader.getBlocksCount();\n\n return Array.from({ length: count }, (_, i) => i).filter(\n (i) => reader.getBlockByIndex(i)?.parentId === parentId\n );\n};\n\n/** Map of block id -> parentId, in flat order. */\nexport const parentMap = (reader: IndexReader): Map<string, string | null> => {\n const count = reader.getBlocksCount();\n const entries = Array.from({ length: count }, (_, i) => reader.getBlockByIndex(i))\n .filter((b): b is { id: string; name: string; parentId: string | null } => b !== undefined)\n .map((b): [string, string | null] => [b.id, b.parentId]);\n\n return new Map(entries);\n};\n\n/** True if `id` descends from `ancestorId` via the parentId chain. */\nexport const isDescendantOf = (\n parentOf: Map<string, string | null>,\n id: string,\n ancestorId: string\n): boolean => {\n const parent = parentOf.get(id) ?? null;\n\n if (parent === null) {\n return false;\n }\n\n return parent === ancestorId || isDescendantOf(parentOf, parent, ancestorId);\n};\n\n/**\n * The flat index of the last block in the contiguous subtree rooted at `index`.\n * In flat (DFS) order a block's descendants sit immediately after it, so this\n * walks forward while blocks remain descendants of the block at `index`.\n * Returns `index` itself when the block has no descendants.\n */\nconst subtreeEndIndex = (reader: IndexReader, index: number): number => {\n const root = reader.getBlockByIndex(index);\n\n if (root === undefined) {\n return index;\n }\n\n const parentOf = parentMap(reader);\n const count = reader.getBlocksCount();\n // Walk forward from index+1 while blocks remain descendants (DFS contiguity).\n // The subtree ends just before the first non-descendant, or at the last block\n // when every follower is a descendant.\n const followers = Array.from({ length: count - (index + 1) }, (_, k) => index + 1 + k);\n const breakAt = followers.find((i) => {\n const b = reader.getBlockByIndex(i);\n\n return b === undefined || !isDescendantOf(parentOf, b.id, root.id);\n });\n\n return breakAt === undefined ? count - 1 : breakAt - 1;\n};\n\n/**\n * The flat index at which a new block should be inserted.\n *\n * `replace` flips the meaning of a before/after `position`: under replace the\n * ref IS the block being overwritten (a \"turn into\"), not a sibling anchor, so\n * it resolves to the ref's OWN flat slot regardless of which parent it lives in\n * — bypassing the sibling-relative parent guard that would otherwise redirect a\n * nested target to the requested parent's end and replace the wrong block.\n */\nexport const resolveInsertIndex = (\n reader: IndexReader,\n parentId: string | null,\n position: InsertPosition,\n replace = false\n): number => {\n if (typeof position === 'object') {\n const ref = 'before' in position ? position.before : position.after;\n const refIndex = reader.getBlockIndex(ref);\n\n if (replace && refIndex !== undefined) {\n return refIndex;\n }\n\n const refParent =\n refIndex === undefined ? undefined : reader.getBlockByIndex(refIndex)?.parentId ?? null;\n\n // before/after is sibling-relative: the ref must be a child of the requested\n // parent. When the ref is missing or lives in a DIFFERENT parent, the\n // parentId constraint wins — fall back to appending at the end of the\n // requested parent rather than splicing into an unrelated subtree (the\n // cross-parent mis-place) or silently landing at the document end.\n if (refIndex === undefined || refParent !== parentId) {\n return resolveInsertIndex(reader, parentId, 'end');\n }\n\n // 'after' must clear the ref's entire subtree, not just the ref node, or the\n // new block splits the ref's descendants in flat (DFS) order.\n return 'before' in position ? refIndex : subtreeEndIndex(reader, refIndex) + 1;\n }\n\n if (parentId === null) {\n return position === 'start' ? 0 : reader.getBlocksCount();\n }\n\n const parentIndex = reader.getBlockIndex(parentId);\n\n if (parentIndex === undefined) {\n return reader.getBlocksCount();\n }\n\n if (position === 'start') {\n const childIndices = childFlatIndices(reader, parentId);\n\n return childIndices.length === 0 ? parentIndex + 1 : childIndices[0];\n }\n\n // 'end': insert after the parent's last descendant.\n return subtreeEndIndex(reader, parentIndex) + 1;\n};\n\n/** The flat toIndex for editor.blocks.move. */\nexport const resolveMoveIndex = (reader: IndexReader, target: MoveTarget): number => {\n if ('toIndex' in target) {\n // Blok's Blocks.move() silently no-ops on an out-of-range index, so clamp\n // an explicit toIndex into [0, count-1] rather than dropping the move.\n const lastIndex = Math.max(0, reader.getBlocksCount() - 1);\n\n return Math.min(Math.max(target.toIndex, 0), lastIndex);\n }\n\n const ref = 'before' in target ? target.before : target.after;\n const refIndex = reader.getBlockIndex(ref);\n\n if (refIndex === undefined) {\n return reader.getBlocksCount();\n }\n\n // 'after' must clear the ref's entire subtree (see resolveInsertIndex), or the\n // moved block lands among the ref's descendants instead of past them.\n return 'before' in target ? refIndex : subtreeEndIndex(reader, refIndex) + 1;\n};\n","import type { Blok, BlockToolData, BlockTuneData, OutputBlockData, OutputData, MarkdownImportConfig } from '@bloklabs/core';\n// src/components/utils/blocks-api.ts\nimport { ToolNotFoundError } from '../errors/tool-not-found';\n\nimport { flattenTree } from '../../shared/flatten-tree';\nimport {\n snapshotNodes,\n resolveInsertIndex,\n resolveMoveIndex,\n parentMap,\n isDescendantOf,\n type BlockNode,\n type CaretTarget,\n type IndexReader,\n type InsertPosition,\n type InsertSpec,\n type MoveTarget,\n type TreeInsertSpec,\n type UseBlocksApi,\n} from './blocks-tree';\n\n/** Adapt the live editor to the IndexReader the snapshot helpers expect. */\nexport const readerFor = (editor: Blok): IndexReader => {\n const blocks = editor.blocks;\n\n return {\n getBlocksCount: () => blocks.getBlocksCount(),\n getBlockByIndex: (i: number) => {\n const b = blocks.getBlockByIndex(i);\n\n return b === undefined ? undefined : { id: b.id, name: b.name, parentId: b.parentId };\n },\n getBlockIndex: (id: string) => blocks.getBlockIndex(id),\n };\n};\n\n/**\n * Stable API returned while the editor is null (before the adapter resolves).\n * Every read returns empty/null and every MUTATOR is a no-op — EXCEPT\n * `transact`/`transactWithoutCapture`, which still invoke their callback so a\n * consumer wrapping conditional work in `transact` still runs that work even\n * pre-ready.\n */\nexport const EMPTY_API: UseBlocksApi = {\n getById: () => null,\n getChildren: () => [],\n insert: () => null,\n insertMany: () => [],\n insertTree: () => null,\n insertMarkdown: async () => [],\n exportMarkdown: async () => '',\n move: () => undefined,\n nest: () => undefined,\n unnest: () => undefined,\n remove: () => undefined,\n update: () => undefined,\n convert: () => undefined,\n // Not a no-op: still runs the callback (see EMPTY_API doc above).\n transact: (fn: () => void) => fn(),\n // Like transact, still runs the callback even pre-ready.\n transactWithoutCapture: (fn: () => void) => fn(),\n getBlocksCount: () => 0,\n getCurrentBlockIndex: () => -1,\n getBlockByIndex: () => null,\n getBlockByElement: () => null,\n getBlockData: () => null,\n getBlockIndex: () => null,\n composeBlockData: async () => ({}),\n renderFromHTML: async () => undefined,\n insertOutputData: () => [],\n splitBlock: () => null,\n insertInsideParent: () => null,\n render: async () => undefined,\n clear: async () => undefined,\n isSyncingFromYjs: () => false,\n};\n\n/**\n * Read the changed block's id out of a `block changed` payload, tolerating any\n * shape that is not core's `{ event: { detail: { target } } }`.\n * @param payload - whatever the dispatcher handed the listener\n * @returns the target block id, or null when the payload does not carry one\n */\nconst changedBlockId = (payload: unknown): string | null => {\n const detail = (payload as { event?: { detail?: { target?: { id?: unknown } } } } | undefined)\n ?.event?.detail?.target?.id;\n\n return typeof detail === 'string' ? detail : null;\n};\n\n/**\n * Does a `block changed` event touch the subtree rooted at `withinId`?\n *\n * The reactivity filter behind `useBlocks(editor, { within })` in all three\n * adapters. Without it every consumer of `useBlocks` re-renders on every change\n * anywhere in the document — so a container block that only renders its own\n * children still re-rendered on each keystroke in an unrelated block, and a page\n * of N such containers turned one keystroke into N re-renders.\n *\n * INDETERMINATE READS AS \"TOUCHED\". The walk resolves ancestry through the LIVE\n * tree, and a removal commonly emits after the block is already gone, so its\n * parent chain cannot be read. Answering `false` there would leave a container\n * rendering a child that no longer exists; answering `true` costs one extra\n * render pass. Same for a payload with no readable target.\n *\n * Ancestry is walked UPWARD one `getById` at a time rather than snapshotted with\n * `parentMap`: this runs on every emission — i.e. on every keystroke — so it must\n * cost O(depth), not O(document).\n * @param editor - the live Blok instance\n * @param payload - the `block changed` payload\n * @param withinId - id of the block whose subtree is the scope\n * @returns true when the change is inside the scope (or cannot be placed)\n */\nexport const changeTouchesSubtree = (\n editor: Blok,\n payload: unknown,\n withinId: string\n): boolean => {\n const targetId = changedBlockId(payload);\n\n if (targetId === null) {\n return true;\n }\n\n /** Ids already visited on this walk — one Set for the whole climb. */\n const seen = new Set<string>();\n\n /**\n * Walk one link up the parentId chain.\n * @param id - the block to test, or null once the root is passed\n * @returns true when `withinId` is `id` or one of its ancestors\n */\n const climbs = (id: string | null): boolean => {\n if (id === null) {\n return false;\n }\n\n if (id === withinId) {\n return true;\n }\n\n // A parentId cycle is a corrupt tree, not a scope hit — bail rather than spin.\n if (seen.has(id)) {\n return false;\n }\n\n seen.add(id);\n\n const node = editor.blocks.getById(id);\n\n // The target (or one of its ancestors) is no longer in the tree.\n if (node === null || node === undefined) {\n return true;\n }\n\n return climbs(node.parentId);\n };\n\n return climbs(targetId);\n};\n\n/**\n * Build the framework-agnostic, id/parentId-relative block-tree API over a LIVE\n * editor. Mutators route through the editor-level `blocks` API (core's\n * chokepoints), so undo/redo and Yjs sync are inherited rather than\n * re-implemented; readers enumerate the live tree on every call.\n *\n * This is the shared engine behind both the React (`useSyncExternalStore`) and\n * Vue (`shallowRef` version) `useBlocks` wrappers — one implementation so the\n * two adapters cannot drift. Each adapter supplies the `onRead` seam:\n *\n * - React leaves it the default no-op: `useSyncExternalStore` re-renders the\n * whole component on `block changed`, and the reads run live during that\n * render, so no per-call dependency tracking is needed.\n * - Vue passes `() => { void version.value }` so a read inside a `computed` /\n * template touches the reactive version ref and re-runs on every structural\n * mutation.\n *\n * `onRead` is invoked at the top of every read method; mutators never call it.\n * The editor MUST be the raw (non-proxied) instance — adapters `toRaw`-unwrap\n * before calling, so a Vue reactive proxy never reaches core (Risk R0).\n *\n * @param editor - the live Blok instance (never null; callers gate on EMPTY_API)\n * @param onRead - reactivity seam called at the start of each read (default no-op)\n */\nexport const createBlocksApiForEditor = (\n editor: Blok,\n onRead: () => void = () => undefined\n): UseBlocksApi => {\n const reader = readerFor(editor);\n\n const getById = (id: string): BlockNode | null => {\n onRead();\n const nodes = snapshotNodes(reader);\n\n return nodes.find((n) => n.id === id) ?? null;\n };\n\n const getChildren = (parentId: string | null): BlockNode[] => {\n onRead();\n\n return snapshotNodes(reader).filter((n) => n.parentId === parentId);\n };\n\n const transact = (fn: () => void): void => {\n if (editor.blocks.transact !== undefined) {\n editor.blocks.transact(fn);\n } else {\n fn();\n }\n };\n\n /** Flat list of id + all transitive descendants, via the parentId graph. */\n const collectSubtreeIds = (rootId: string): string[] => {\n const nodes = snapshotNodes(reader);\n const childrenOf = new Map<string, string[]>();\n\n for (const n of nodes) {\n if (n.parentId === null) {\n continue;\n }\n const bucket = childrenOf.get(n.parentId) ?? [];\n\n bucket.push(n.id);\n childrenOf.set(n.parentId, bucket);\n }\n\n const out: string[] = [];\n const visited = new Set<string>();\n const stack: string[] = [rootId];\n\n // A parentId cycle (possible from a concurrent remote Yjs reparent) would\n // make this DFS spin forever — track visited ids and skip re-entry so each\n // block is emitted at most once and the traversal always terminates.\n while (stack.length > 0) {\n const id = stack.pop() as string;\n\n if (visited.has(id)) {\n continue;\n }\n visited.add(id);\n out.push(id);\n const kids = childrenOf.get(id);\n\n if (kids !== undefined) {\n stack.push(...kids);\n }\n }\n\n return out;\n };\n\n /** Each subtree member's parentId, captured from the current snapshot. */\n const captureSubtreeParents = (rootId: string): Array<{ id: string; parentId: string | null }> => {\n const parentOf = new Map(snapshotNodes(reader).map((n) => [n.id, n.parentId]));\n\n return collectSubtreeIds(rootId).map((id) => ({ id, parentId: parentOf.get(id) ?? null }));\n };\n\n /**\n * Relocate id AND its whole subtree to sit contiguously starting at a\n * PRE-removal flat slot. Blok's Blocks.move() is post-removal index space and\n * only carries DOM-contained descendants (resortNestedBlocks) — indent /\n * parentId-nested children are NOT, so move each subtree member that a single\n * root move didn't already pull into place. Keeps the flat array DFS-contiguous,\n * the invariant the flat-index insert API and getChildren ordering depend on.\n */\n const relocateSubtree = (rootId: string, preRemovalSlot: number): 'moved' | 'skipped' | 'blocked' => {\n // Subtree members in current flat (document) order — root first.\n const members = collectSubtreeIds(rootId)\n .map((id) => ({ id, idx: editor.blocks.getBlockIndex(id) }))\n .filter((m): m is { id: string; idx: number } => m.idx !== undefined)\n .sort((a, b) => a.idx - b.idx)\n .map((m) => m.id);\n\n const rootFrom = editor.blocks.getBlockIndex(rootId);\n\n if (rootFrom === undefined) {\n return 'blocked';\n }\n\n // Self-overlap guard. `preRemovalSlot` is the destination the caller\n // computed as the END of the (new or former) parent's WHOLE subtree — and\n // when that parent is an ANCESTOR of the relocating block (always so for\n // unnest, and for a nest into a block this one already sits under), that\n // span still CONTAINS this block's own subtree. Moving the root to a slot\n // at the tail of (or inside) its own footprint splices it in right after\n // one of its OWN descendants; core's post-move auto-heal then reparents the\n // block under that descendant (setBlockParent(B, B) when the neighbour is\n // the block's last child), which BlockHierarchy REFUSES with a thrown cycle\n // error — crashing the caller. But the block is already DFS-contiguous at\n // that destination (its subtree is the tail of the parent's subtree), so\n // the relocation is a no-op: skip the move and report 'skipped', leaving the\n // caller to assert the reparent. Window: `rootFrom < preRemovalSlot <=\n // subtreeEnd + 1`. A backward move (`preRemovalSlot <= rootFrom`) or a\n // genuine forward move past unrelated content (`preRemovalSlot > subtreeEnd\n // + 1`) is untouched.\n //\n // 'skipped' (vs 'moved') is reported DISTINCTLY because no `editor.blocks.\n // move()` ran — so core's post-move parent auto-heal never fired. nest/unnest\n // re-assert the root's parent explicitly (reparentSubtree), so they don't\n // care; but move() leans on that auto-heal for the root's parent-adoption, so\n // it must apply the adopted parent itself on this path (see move()).\n const subtreeEnd = collectSubtreeIds(rootId)\n .map((memberId) => editor.blocks.getBlockIndex(memberId))\n .filter((i): i is number => i !== undefined)\n .reduce((max, i) => Math.max(max, i), rootFrom);\n\n if (preRemovalSlot > rootFrom && preRemovalSlot <= subtreeEnd + 1) {\n return 'skipped';\n }\n\n // Defensive clamp into [0, count-1]: Blok's move() silently no-ops on an\n // out-of-range index, so an over-large preRemovalSlot would strand the\n // root instead of appending it. (In practice resolveInsertIndex stays in\n // range; this guards a concurrently-shrunk tree.)\n const lastIndex = Math.max(0, editor.blocks.getBlocksCount() - 1);\n const rootTarget = Math.min(\n Math.max(rootFrom < preRemovalSlot ? preRemovalSlot - 1 : preRemovalSlot, 0),\n lastIndex\n );\n\n editor.blocks.move(rootTarget, rootFrom);\n\n // Detect a BLOCKED relocation: Blok's move() clamps a cross-`column`-\n // boundary move to a no-op. If the root could not reach its target (it\n // didn't move and wasn't already there), the relocation failed — report\n // it so the caller skips the reparent that would otherwise corrupt DFS\n // contiguity (a child wedged outside its parent's flat run). A legitimate\n // no-op (already at target, rootFrom === rootTarget) still counts as\n // relocated so an in-place nest/unnest reparents as intended.\n if (rootFrom !== rootTarget && editor.blocks.getBlockIndex(rootId) === rootFrom) {\n return 'blocked';\n }\n\n // Place each descendant immediately after the previously-positioned member,\n // re-reading the anchor's LIVE index every iteration. A cached root index\n // (rootNew + k + 1) only holds for a BACKWARD relocation, where descendants\n // already sit after the root. For a FORWARD relocation each descendant\n // move() splices an element out from BEFORE the root, sliding the root (and\n // a cached index) down one slot per step — so the target overshoots, trips\n // Blocks.move()'s out-of-range no-op guard, and strands the descendant.\n // Re-anchoring to the predecessor's current slot absorbs the drift in both\n // directions and keeps the subtree DFS-contiguous. A descendant already in\n // place (carried by resortNestedBlocks for a DOM-nested child) is skipped.\n // The anchor for the k-th descendant is the (k-1)-th — read live each step.\n const descendants = members.filter((memberId) => memberId !== rootId);\n\n descendants.forEach((memberId, k) => {\n const anchorId = k === 0 ? rootId : descendants[k - 1];\n const from = editor.blocks.getBlockIndex(memberId);\n const anchor = editor.blocks.getBlockIndex(anchorId);\n\n if (from === undefined || anchor === undefined) {\n return;\n }\n const target = anchor + 1;\n\n if (from !== target) {\n editor.blocks.move(from < target ? target - 1 : target, from);\n }\n });\n\n return 'moved';\n };\n\n // Reparent `id` (root → newParentId, descendants → their original parent).\n // Re-asserting after relocateSubtree heals move()'s auto-reparent (which sets\n // a moved block's parentId to its new neighbour) and never relocates the flat\n // array, so contiguity established by relocateSubtree is preserved.\n const reparentSubtree = (\n members: Array<{ id: string; parentId: string | null }>,\n rootId: string,\n newParentId: string | null\n ): void => {\n for (const m of members) {\n editor.blocks.setBlockParent(m.id, m.id === rootId ? newParentId : m.parentId);\n }\n };\n\n // Re-assert ONLY the descendants' captured parents after a subtree relocation,\n // leaving the ROOT's parent as core's post-move auto-heal set it — used by\n // move(), whose documented side effect is that the root ADOPTS the parent of\n // the slot it lands in while its subtree travels with it.\n const reassertDescendantParents = (\n members: Array<{ id: string; parentId: string | null }>,\n rootId: string\n ): void => {\n members\n .filter((m) => m.id !== rootId)\n .forEach((m) => editor.blocks.setBlockParent(m.id, m.parentId));\n };\n\n /**\n * Whether `id` is a DIRECT child of a `column` block. Column membership is\n * owned by the drag UI, so a programmatic nest/unnest that would change it is\n * a graceful no-op (see the nest/unnest docs). Checking this EXPLICITLY makes\n * that contract reliable: relying on core's move-clamp alone leaks, because\n * when the relocation needs no actual move (a tail column child already sits\n * at its relocation target) no boundary-crossing move fires, so nothing\n * clamps and the reparent would slip through.\n */\n const isColumnChild = (id: string): boolean => {\n const parent = getById(id)?.parentId ?? null;\n\n return parent !== null && getById(parent)?.type === 'column';\n };\n\n /**\n * Nest `id` (and its whole subtree) under `parentId`, as one undo step.\n * No-op when either id is unknown (probed via the silent snapshot, NOT\n * getBlockIndex, which warns on unknown ids), or when `parentId` is `id`\n * itself or one of `id`'s own descendants — that would form a cycle, which\n * core's setBlockParent THROWS on, so the hook guards it up front.\n *\n * Column boundary caveat: nesting a block that lives inside a `column`, or\n * nesting directly INTO one, is a GRACEFUL no-op — column membership is owned\n * by the drag UI. This is detected explicitly (via the block's and target's\n * parent type), so the no-op holds even when no boundary-crossing move fires.\n * Returns void.\n */\n const nest = (id: string, parentId: string): void => {\n if (getById(parentId) === null || getById(id) === null) {\n return;\n }\n\n // Cycle guard: a block can't become a child of itself or of one of its\n // own descendants. Without this, the relocate/reparent reaches core's\n // setBlockParent, which throws on a cycle and crashes the caller.\n if (parentId === id || isDescendantOf(parentMap(reader), parentId, id)) {\n return;\n }\n\n // Column-boundary no-op: pulling a block out of a `column`, or pushing one\n // directly into a column, changes column membership — owned by the drag UI.\n if (isColumnChild(id) || getById(parentId)?.type === 'column') {\n return;\n }\n\n // Relocate id's whole subtree to after the new parent's existing subtree,\n // THEN assert the parents. Blok keeps the flat array as the canonical\n // document order, and the flat-index insert API only resolves a parent's\n // \"end\" slot when that parent's descendants are contiguous — a bare reparent\n // (no relocation) would wedge unrelated blocks between the parent and its new\n // child, corrupting later inserts/reads. Mirrors the drag move-then-reparent.\n //\n // Only reparent when the relocation actually placed the block: a clamped\n // cross-column move leaves it where it was, and reparenting in place would\n // break DFS contiguity.\n const members = captureSubtreeParents(id);\n\n transact(() => {\n // reparentSubtree sets the root's parent EXPLICITLY, so nest is correct on\n // both the 'moved' and 'skipped' paths — it only bails on a 'blocked'\n // (clamped cross-column) relocation.\n if (relocateSubtree(id, resolveInsertIndex(reader, parentId, 'end')) !== 'blocked') {\n reparentSubtree(members, id, parentId);\n }\n });\n };\n\n /**\n * Promote `id` (and its subtree) to root, as one undo step. No-op when the\n * id is unknown or already at root. Same column-boundary caveat as\n * {@link nest}: unnesting a `column` member out to root is a graceful no-op\n * (column membership changes go through the drag UI). Returns void.\n */\n const unnest = (id: string): void => {\n const node = getById(id);\n\n if (node === null) {\n return;\n }\n const parentId = node.parentId;\n\n if (parentId === null) {\n return;\n }\n\n // Column-boundary no-op: a column member is detached only via the drag UI.\n if (isColumnChild(id)) {\n return;\n }\n\n // Move id's subtree out past its former parent's whole subtree before\n // clearing the parent, so the promoted block doesn't strand itself between\n // the parent and its remaining children (which would break contiguity).\n // As with nest, only clear the parent when the relocation succeeded — a\n // clamped cross-column move must stay a graceful no-op.\n const members = captureSubtreeParents(id);\n\n transact(() => {\n // As with nest, reparentSubtree asserts the root's (null) parent on both\n // 'moved' and 'skipped'; only a 'blocked' clamp keeps it a no-op.\n if (relocateSubtree(id, resolveInsertIndex(reader, parentId, 'end')) !== 'blocked') {\n reparentSubtree(members, id, null);\n }\n });\n };\n\n const remove = (id: string): void => {\n if (editor.blocks.getBlockIndex(id) === undefined) {\n return;\n }\n\n // Remove the block AND its descendants. Blok's single-block delete promotes\n // a (non-columns) container's children to root, which would orphan the\n // nested structure the caller meant to discard. Delete deepest-first (by\n // descending flat index) so a parent is childless by the time it's deleted\n // (no promotion). One undo step.\n //\n // Re-resolve each member's index by id AT DELETE TIME rather than reusing a\n // pre-captured snapshot: a core delete can cascade (deleting a column's last\n // child auto-removes the empty column) or shift indices, so a stale index\n // could target the wrong — or an already-gone — block.\n const orderedIds = collectSubtreeIds(id)\n .map((subId) => ({ subId, index: editor.blocks.getBlockIndex(subId) }))\n .filter((m): m is { subId: string; index: number } => m.index !== undefined)\n .sort((a, b) => b.index - a.index)\n .map((m) => m.subId);\n\n transact(() => {\n for (const subId of orderedIds) {\n const index = editor.blocks.getBlockIndex(subId);\n\n // Already removed by a cascading delete of one of its descendants.\n if (index === undefined) {\n continue;\n }\n void editor.blocks.delete(index, false);\n }\n });\n };\n\n /**\n * Move `id` to a flat slot, as a single operation. No-op when `id` is\n * unknown (probed via the silent snapshot, NOT getBlockIndex, which warns on\n * unknown ids); when a relative `{ before|after }` target references `id`\n * itself, one of its descendants (a block can't be a sibling of its own\n * child), or a ref that does not exist (an unresolved relative target must\n * not silently dump the block at the document end); or for ANY absolute\n * `{ toIndex }` of a block that HAS descendants (a multi-block subtree can't\n * land on one index — see the subtree note below). Guards run BEFORE the\n * index is resolved into a final move.\n *\n * Parent-adoption side effect: `before`/`after` make the moved block a\n * SIBLING of the ref — it adopts the REF's parent (moving before/after a\n * child of a container nests it into that container; moving before/after a\n * root block unnests it to root). `after` clears the ref's WHOLE subtree, so\n * the block lands past the ref's descendants, not among them. The adopted\n * parent is the ref's — NOT the parent of whatever block happens to sit at the\n * landing slot, which would nest under the ref for `after` a ref-with-children.\n * Use {@link nest}/{@link unnest} to change the parent without choosing a\n * sibling slot. Returns void.\n *\n * Subtree-aware: a block WITH descendants relocates its WHOLE subtree as one\n * undo step (core's single move() carries only DOM-contained descendants, so\n * a naive move would strand indent/parentId-nested children before their\n * parent and corrupt DFS contiguity). Only relative `{ before|after }`\n * targets name an unambiguous slot for a multi-block subtree; an absolute\n * `{ toIndex }` of a block that HAS descendants is ambiguous (k blocks can't\n * all land on one index) and is a graceful no-op — use `{ before|after }` to\n * relocate a subtree.\n */\n const move = (id: string, target: MoveTarget): void => {\n // Silent existence probe (NOT getBlockIndex, which warns on unknown ids).\n if (getById(id) === null) {\n return;\n }\n // id is known, so getBlockIndex won't warn.\n const fromIndex = editor.blocks.getBlockIndex(id);\n\n if (fromIndex === undefined) {\n return;\n }\n\n if (!('toIndex' in target)) {\n const ref = 'before' in target ? target.before : target.after;\n\n // A relative target can't reference the block itself or any of its own\n // descendants — a block can't become a sibling of its child.\n if (ref === id || isDescendantOf(parentMap(reader), ref, id)) {\n return;\n }\n\n // An unresolved relative ref must NOT fall through to a relocate-to-end:\n // a missing target is a no-op, not a surprise jump to the document end.\n if (getById(ref) === null) {\n return;\n }\n }\n // NB: an absolute { toIndex } needs no early guard here. A block WITH\n // descendants no-ops EVERY toIndex move in the subtree branch below\n // (ambiguous for a multi-block subtree); a leaf has no own-subtree range to\n // land inside. So a dedicated \"toIndex inside own subtree\" guard would be\n // dead code — the subtree-branch no-op already covers the cycle it guarded.\n\n // Subtree-aware relocation. A block WITH descendants can't ride a single\n // core move(): core carries only DOM-contained descendants (resortNested\n // Blocks), so indent/parentId-nested children are left at their old slot —\n // stranded BEFORE their now-moved parent in flat order, breaking the DFS\n // contiguity getChildren ordering and flat-index inserts depend on, and\n // corrupting saved document order. Relocate the whole subtree (as\n // nest/unnest do) and re-assert each descendant's own parent; the ROOT\n // keeps the parent core's post-move auto-heal gives it — move()'s\n // documented parent-adoption side effect — so only descendants are\n // re-parented. A blocked relocation (a clamped cross-`column` move) leaves\n // everything in place, a graceful no-op like nest/unnest. An absolute\n // { toIndex } is ambiguous for a multi-block subtree (see the move() doc),\n // so it is a graceful no-op here — relative targets relocate the subtree.\n // A leaf block (no descendants) falls through to the single-move fast path.\n const subtreeMembers = captureSubtreeParents(id);\n\n if (subtreeMembers.length > 1) {\n if ('toIndex' in target) {\n return;\n }\n\n const preRemovalSlot = resolveMoveIndex(reader, target);\n // The relative ref whose parent the moved block adopts (toIndex returned\n // above, so target is { before | after }).\n const ref = 'before' in target ? target.before : target.after;\n\n transact(() => {\n const outcome = relocateSubtree(id, preRemovalSlot);\n\n if (outcome === 'blocked') {\n return;\n }\n reassertDescendantParents(subtreeMembers, id);\n\n // Adopt the REF's parent (sibling-of-ref) on BOTH the 'moved' and\n // 'skipped' paths. The position is already sibling-of-ref: resolveMoveIndex\n // clears the ref's WHOLE subtree for `after` and uses the ref's own slot\n // for `before`, so id lands as the ref's sibling. The parent must match.\n // Core's post-move auto-heal does NOT give that — it adopts the parent of\n // the block at the landing SLOT (pre-removal), which for `after` a\n // ref-with-descendants is the ref's last descendant (parent = the ref →\n // nests id UNDER the ref) and for `before` a ref whose flat predecessor\n // sits in another container is that predecessor's parent. On the 'skipped'\n // path no move() ran, so no auto-heal fired at all. Assert ref.parentId so\n // position and parent agree regardless of path. Guarded (mirrors\n // insertWithinTransaction) so a same-container reorder — the common case,\n // where the landed parent already matches — fires no redundant reparent.\n // Can't cycle: ref is neither id nor a descendant (guarded above), so\n // ref's parent is outside id's subtree.\n const intendedParent = getById(ref)?.parentId ?? null;\n\n if ((getById(id)?.parentId ?? null) !== intendedParent) {\n editor.blocks.setBlockParent(id, intendedParent);\n }\n });\n\n return;\n }\n\n const resolved = resolveMoveIndex(reader, target);\n\n // Blok's Blocks.move() removes the block (splice fromIndex) BEFORE\n // re-inserting at toIndex, so toIndex lives in the POST-removal index\n // space. For a relative (before/after) forward move the reference index\n // shifts down by one once the block is removed, so compensate — this also\n // keeps a move-to-end within Blok's `toIndex < length` bound. A literal\n // { toIndex } is the caller's explicit final resting index: pass through.\n const isRelative = !('toIndex' in target);\n const toIndex = isRelative && fromIndex < resolved ? resolved - 1 : resolved;\n\n if (!isRelative) {\n // Absolute { toIndex }: the caller chose the slot, so let core's auto-heal\n // adopt that slot's container (the documented absolute-move semantics).\n editor.blocks.move(toIndex, fromIndex);\n\n return;\n }\n\n // Relative leaf move: same sibling-of-ref rule as the subtree branch — the\n // moved block adopts the REF's parent, not the landing-slot neighbour's\n // (which auto-heal would give: the ref's descendant for `after`, or a\n // cross-container predecessor for `before`). Assert it in the same undo step\n // as the move, guarded so a same-container reorder fires no redundant\n // reparent. Can't cycle: ref is guarded to be neither id nor a descendant,\n // and a leaf has no descendants for ref's parent to fall inside.\n const ref = 'before' in target ? target.before : target.after;\n\n transact(() => {\n editor.blocks.move(toIndex, fromIndex);\n const intendedParent = getById(ref)?.parentId ?? null;\n\n if ((getById(id)?.parentId ?? null) !== intendedParent) {\n editor.blocks.setBlockParent(id, intendedParent);\n }\n });\n };\n\n /**\n * Perform one insert (create + intended-parent assertion) WITHOUT opening a\n * transaction — the caller owns the undo grouping. `insert` wraps a single\n * call in its own transact; `insertMany` shares ONE transact across the whole\n * batch so the bulk insert is a single undo step. Returns the created node,\n * or null when nothing was inserted (idempotent hit returns the existing\n * node; a guard failure returns null).\n */\n const insertWithinTransaction = (spec: InsertSpec): { node: BlockNode | null; created: boolean } => {\n const parentId = spec.parentId ?? null;\n const position = spec.position ?? 'end';\n const data = spec.data ?? {};\n // Programmatic insert must not steal the caret unless explicitly asked.\n const needToFocus = spec.focus ?? false;\n const replace = spec.replace ?? false;\n\n // Every pre-insert guard (id-exists, dangling-parent, missing-ref) and the\n // replace-parent lookup used to call `getById`, which re-enumerates the\n // WHOLE tree each time — O(probes·n) per spec, O(k·probes·n) per batch.\n // The tree can't change until `editor.blocks.insert` runs below, so take\n // ONE snapshot here and resolve every pre-insert probe against it.\n const preById = new Map(snapshotNodes(reader).map((n) => [n.id, n]));\n const probe = (id: string): BlockNode | null => preById.get(id) ?? null;\n\n // Idempotent insert-if-absent: a stable explicit id that already exists\n // returns the existing node without inserting a duplicate, so a re-running\n // effect is safe. Probe via the silent snapshot getById, NOT\n // editor.blocks.getBlockIndex — the latter logs a `warn` for any unknown\n // id, which would spam the console on this (expected-absent) happy path.\n //\n // Skipped under `replace`: a replace is an explicit overwrite, not an\n // insert, so an existing id must not short-circuit it (the two would\n // otherwise silently conflict and replace nothing).\n if (spec.id !== undefined && !replace) {\n const existing = probe(spec.id);\n\n if (existing !== null) {\n // Insert-if-absent hit: the block already existed, nothing was created.\n // insert() still returns the existing node (documented), but insertMany\n // must EXCLUDE it from its created[] result — hence created: false.\n return { node: existing, created: false };\n }\n }\n\n // A dangling parentId would make core throw (dev) or silently misplace the\n // block at the document end (prod). Honor the null contract instead. Probe\n // via the silent snapshot getById, NOT editor.blocks.getBlockIndex, which\n // logs a `warn` for any unknown id and would spam the console on this\n // expected-absent no-op path. Skipped under replace: a replace ignores\n // parentId entirely (the overwritten block's own parent governs), so a\n // stale parentId must not abort the overwrite.\n if (!replace && parentId !== null && probe(parentId) === null) {\n return { node: null, created: false };\n }\n\n // A replace targets the before/after ref block ITSELF (the \"turn into\"\n // block being overwritten), not a sibling anchor. It therefore REQUIRES an\n // object position naming that ref:\n // - with position 'start'/'end' (or omitted) there is no target ref, so\n // a replace has nothing to overwrite — return null rather than silently\n // overwriting whatever block happens to sit at the resolved slot;\n // - with an object position whose ref doesn't exist there is likewise\n // nothing to overwrite — return null instead of falling through to\n // resolveInsertIndex's end-slot fallback (which would insert/replace at\n // the wrong place and reparent a dangling target).\n // Validation is skipped for a plain insert (above), so this is the only\n // guard that protects the replace path.\n if (replace) {\n if (typeof position !== 'object') {\n return { node: null, created: false };\n }\n\n const replaceTargetRef = 'before' in position ? position.before : position.after;\n\n if (probe(replaceTargetRef) === null) {\n return { node: null, created: false };\n }\n }\n\n // A plain insert with an object position naming a ref that does NOT exist\n // must be a no-op (return null), NOT a silent append at the document/parent\n // end. resolveInsertIndex falls back to the end slot for an unresolved ref,\n // which would dump the block somewhere surprising — a DX footgun. Mirror\n // move(), which already bails on a missing relative ref. (Skipped under\n // replace: the block above already validated the replace ref.)\n if (!replace && typeof position === 'object') {\n const positionTargetRef = 'before' in position ? position.before : position.after;\n\n if (probe(positionTargetRef) === null) {\n return { node: null, created: false };\n }\n }\n\n const flatIndex = resolveInsertIndex(reader, parentId, position, replace);\n\n // A replace is a positional type-swap that PRESERVES the replaced block's\n // parent link, so the intended parent is the target's existing parent, not\n // the caller's (root-defaulting) parentId. Capture it from the pre-insert\n // snapshot so the post-insert assertion re-nests the replacement correctly\n // instead of un-nesting it to root. A plain insert uses parentId as-is.\n const positionRef = ((): string | null => {\n if (typeof position !== 'object') {\n return null;\n }\n\n return 'before' in position ? position.before : position.after;\n })();\n const replaceRef = replace ? positionRef : null;\n const intendedParentId =\n replaceRef !== null ? probe(replaceRef)?.parentId ?? null : parentId;\n\n const created = ((): { id: string } | null | undefined => {\n try {\n return editor.blocks.insert(spec.type, data, {}, flatIndex, needToFocus, replace, spec.id, spec.tunes);\n } catch (error) {\n // The only EXPECTED throw here is an unknown/missing tool — core throws\n // a typed ToolNotFoundError. (A missing replace TARGET is a bare Error,\n // not this type, so it would re-throw — but the replace ref is already\n // pre-validated above, so it never reaches here.) Honor the null contract\n // for ToolNotFoundError; re-throw anything else so a genuine\n // bug surfaces instead of being masked as a null return. Keyed on the\n // error TYPE, not a 'not found' substring, so an unrelated error whose\n // message happens to contain \"not found\" is not wrongly swallowed.\n if (error instanceof ToolNotFoundError) {\n return null;\n }\n throw error;\n }\n })();\n\n if (created === undefined || created === null) {\n return { node: null, created: false };\n }\n\n // Assert the intended parent. Core derives a new block's parent from its\n // flat predecessor, so a block appended right after a `column` child is\n // auto-nested into that column. We know the caller's intent: for a\n // parented insert set the parent; for a root insert (parentId === null)\n // override back to root ONLY if core nested it, keeping the natural\n // `insert({ position: 'end' })` a root sibling instead of a stowaway. For\n // a replace, intendedParentId is the overwritten block's own parent, so\n // the replacement keeps its place in the tree.\n // ONE post-insert snapshot for both the landed-parent check and the return\n // node (was two separate getById enumerations). A freshly-created block has\n // no children, so reparenting it only flips its own parentId — its derived\n // contentIds stay `[]`. We therefore reconstruct the corrected node in place\n // rather than re-enumerating the tree a third time after setBlockParent.\n const createdNode = snapshotNodes(reader).find((n) => n.id === created.id) ?? null;\n const landedParentId = createdNode?.parentId ?? null;\n\n const node =\n landedParentId === intendedParentId\n ? createdNode\n : ((): BlockNode | null => {\n editor.blocks.setBlockParent(created.id, intendedParentId);\n\n return createdNode === null ? null : { ...createdNode, parentId: intendedParentId };\n })();\n\n // Position the caret inside the freshly-created block when the caller asked\n // for a specific spot (beyond the boolean `focus`). Applied only on a real\n // creation — an insert-if-absent hit returned earlier, so it never reaches\n // here. setToBlock takes the block id directly.\n if (spec.caret !== undefined) {\n editor.caret.setToBlock(created.id, spec.caret.position ?? 'default', spec.caret.offset ?? 0);\n }\n\n return { node, created: true };\n };\n\n /**\n * Insert one block. Returns the created {@link BlockNode}, or null when the\n * insert is rejected — an unknown tool type (core \"…not found\"), a dangling\n * `parentId`, or a `replace` whose target ref doesn't exist. An explicit\n * `id` that already exists is insert-if-absent: the existing node is returned\n * and nothing is created (skipped under `replace`, which is an explicit\n * overwrite). Validation runs BEFORE the slot is resolved; a `replace`\n * preserves the overwritten block's parent. Always one atomic undo step.\n *\n * The returned node is a fresh-snapshot view (its `contentIds` are derived\n * per call) — read it immediately; do NOT place it in a `useMemo`/`useEffect`\n * dependency array expecting per-mutation identity.\n */\n const insert = (spec: InsertSpec = {}): BlockNode | null => {\n // Mutable property on a const holder (no `let`): the node captured from\n // inside the transact closure for the post-transact return.\n const result: { node: BlockNode | null } = { node: null };\n\n // Always atomic: a single undo step removes the new block (and, for a\n // parented insert, its reparent) — and gives the insert its own boundary\n // instead of merging into adjacent typing history.\n transact(() => {\n // insert() returns the resolved node — including an insert-if-absent hit's\n // existing node (documented) — so it reads only `.node`, not `.created`.\n result.node = insertWithinTransaction(spec).node;\n });\n\n return result.node;\n };\n\n const insertMany = (specs: InsertSpec[]): BlockNode[] => {\n // An empty batch opens no transaction (no spurious undo boundary).\n if (specs.length === 0) {\n return [];\n }\n\n const created: BlockNode[] = [];\n\n // ONE transact for the whole batch → a single atomic undo step. Each spec\n // still runs the full single-insert path (parent assertion, positioning).\n // Per the documented contract, the result holds ONLY successfully-created\n // nodes: specs that fail to insert (null node) AND insert-if-absent hits\n // (existing block, created: false) are both dropped.\n transact(() => {\n for (const spec of specs) {\n const result = insertWithinTransaction(spec);\n\n if (result.created && result.node !== null) {\n created.push(result.node);\n }\n }\n });\n\n return created;\n };\n\n /**\n * Insert a pre-built nested subtree as ONE atomic operation. See the\n * {@link UseBlocksApi.insertTree} contract. Flattens the spec to a DFS\n * pre-order `OutputBlockData[]` — wiring every node's `parent`/`content`\n * links from ids generated up front — then delegates to core's tree-aware\n * `blocks.insertMany` inside a single transact.\n */\n const insertTree = (spec: TreeInsertSpec): BlockNode | null => {\n const parentId = spec.parentId ?? null;\n const position = spec.position ?? 'end';\n\n // Dangling root parentId: mirror `insert`'s guard via the silent snapshot\n // getById (NOT getBlockIndex, which warns on unknown ids). Reject so the\n // subtree isn't silently dumped at the document end.\n if (parentId !== null && getById(parentId) === null) {\n return null;\n }\n\n // Dangling relative position ref: an object { before|after } naming a block\n // that does not exist must be a no-op, NOT a silent append at the document\n // end (resolveInsertIndex's unresolved-ref fallback). Mirror insert()'s\n // missing-ref guard and reject before flattening anything.\n if (typeof position === 'object') {\n const positionTargetRef = 'before' in position ? position.before : position.after;\n\n if (getById(positionTargetRef) === null) {\n return null;\n }\n }\n\n // Flatten the nested spec to a DFS pre-order array with wired\n // `parent`/`content` links — the same transform used to seed nested data,\n // shared as the pure `flattenTree` helper. `parentId` becomes the root's\n // `parent`. flattenTree throws on an id reused WITHIN the spec (a duplicate\n // would corrupt every id-keyed lookup); a tree insert always creates fresh\n // blocks (NOT insert-if-absent), so that is rejected up front — null,\n // mirroring insert's null contract.\n const flat = (() => {\n try {\n return flattenTree(spec, { parentId: parentId ?? undefined });\n } catch {\n return null;\n }\n })();\n\n if (flat === null) {\n return null;\n }\n\n // External collision: an explicit id already present in the live tree would\n // also create a duplicate-id block. Snapshot the existing ids once and\n // reject if any flat node reuses one. Generated ids never collide.\n const existingIds = new Set(snapshotNodes(reader).map((n) => n.id));\n\n if (flat.some((node) => existingIds.has(node.id))) {\n return null;\n }\n\n const rootId = flat[0].id;\n\n // flattenTree omits `content` on leaves (clean seed-data shape). insertMany\n // wants every node to carry an explicit child-id array — a leaf's\n // `contentIds: []` states \"no children\" rather than leaving it undefined —\n // so stamp the empty array back on before handing the batch to core.\n for (const node of flat) {\n if (node.content === undefined) {\n node.content = [];\n }\n }\n\n const flatIndex = resolveInsertIndex(reader, parentId, position);\n\n // ONE transact for the whole subtree → a single atomic undo step. Core's\n // insertMany composes EVERY node before inserting any, so an unknown tool\n // type throws a typed ToolNotFoundError with nothing inserted. Honor the\n // same null-on-unknown-tool contract as insert/insertMany rather than\n // surfacing the throw to the caller; re-throw any other (genuine-bug)\n // error. Keyed on the error TYPE, not a 'not found' substring.\n try {\n transact(() => {\n editor.blocks.insertMany(flat, flatIndex);\n });\n } catch (error) {\n if (error instanceof ToolNotFoundError) {\n return null;\n }\n throw error;\n }\n\n return getById(rootId);\n };\n\n /**\n * Convert markdown to blocks and insert them ADDITIVELY — see the\n * {@link UseBlocksApi.insertMarkdown} doc for the full contract. Async\n * because the converter is lazy-loaded; the insert itself is one atomic\n * undo step. parentId nesting is supported: top-level converted blocks are\n * reparented under parentId, internally-nested ones keep their parent.\n */\n const insertMarkdown = async (\n markdown: string,\n options?: { parentId?: string | null; position?: InsertPosition; config?: MarkdownImportConfig }\n ): Promise<BlockNode[]> => {\n const parentId = options?.parentId ?? null;\n const position = options?.position ?? 'end';\n\n // A dangling parentId is a no-op (no insert), matching `insert`/`insertMany`.\n if (parentId !== null && getById(parentId) === null) {\n return [];\n }\n\n // A dangling relative position ref is likewise a no-op (no insert), NOT a\n // silent append at the document end — mirror insert()/insertTree's guard.\n if (typeof position === 'object') {\n const positionTargetRef = 'before' in position ? position.before : position.after;\n\n if (getById(positionTargetRef) === null) {\n return [];\n }\n }\n\n // Lazy-load the converter (dynamic import mirrors core's markdown lazy\n // loading and keeps the parser out of the main bundle) and run it,\n // forwarding the optional MarkdownImportConfig so custom-tool consumers can\n // map markdown nodes into their tools (gfm toggle, toolMap, extensions).\n // Both awaits can fail — a chunk-load error or a malformed-markdown throw;\n // swallow them and return [] so a converter failure is a graceful no-op\n // (matching update/convert) rather than an unhandled promise rejection in\n // the caller. This await resolves BEFORE the synchronous transact.\n // Mutable property on a const holder (no `let`): captured from the try.\n const conversion: { blocks: OutputBlockData[] } = { blocks: [] };\n\n try {\n const { markdownToBlocks } = await import('@bloklabs/core/markdown');\n\n conversion.blocks = await markdownToBlocks(markdown, options?.config);\n } catch (error) {\n // Graceful no-op: a converter failure (chunk-load or parse error) returns\n // [] rather than surfacing an unhandled rejection to the caller. But\n // surface it to the console so a genuine converter bug is DISTINGUISHABLE\n // from empty markdown (which returns [] via the blocks.length === 0 path\n // below, without ever reaching this catch) instead of being swallowed\n // silently and losing all diagnostics.\n console.warn('useBlocks.insertMarkdown: markdown conversion failed', error);\n\n return [];\n }\n\n const blocks = conversion.blocks;\n\n // Empty / whitespace-only markdown opens no transaction (no undo boundary).\n if (blocks.length === 0) {\n return [];\n }\n\n // Re-validate the parent AFTER the await: the pre-await existence check can\n // go stale if the parent was removed while the converter was in flight.\n // Stamping a now-dangling parent would orphan the blocks instead of the\n // promised [] no-op, so re-check and bail out here.\n if (parentId !== null && getById(parentId) === null) {\n return [];\n }\n\n // Re-validate the relative position ref after the await too: the target\n // could have been removed while the converter was in flight, in which case\n // inserting at the stale slot would surprise the caller. No-op instead.\n if (typeof position === 'object') {\n const positionTargetRef = 'before' in position ? position.before : position.after;\n\n if (getById(positionTargetRef) === null) {\n return [];\n }\n }\n\n // Nest under the parent by stamping `parent` on each TOP-LEVEL block (one\n // the converter left un-parented). Blocks the markdown nested internally\n // (their `parent` already points at a sibling in this batch) are untouched,\n // so the import's own structure is preserved.\n const seeded: OutputBlockData[] =\n parentId === null\n ? blocks\n : blocks.map((block) =>\n block.parent === undefined || block.parent === null\n ? { ...block, parent: parentId }\n : block\n );\n\n const flatIndex = resolveInsertIndex(reader, parentId, position);\n\n // Mutable property on a const holder (no `let`): captured from inside the\n // transact closure. insertMany returns BlockAPI[] (each has `.id`) — the\n // reliable record of what was created, since the converter's ids may not\n // survive composition. ONE transact → a single atomic undo step.\n const result: { created: Array<{ id: string }> } = { created: [] };\n\n // The insert lives OUTSIDE the conversion try/catch, so an unknown mapped\n // tool (core throws a typed ToolNotFoundError) would otherwise surface as an\n // unhandled promise rejection. Honor the same null-on-unknown-tool contract\n // as insertTree — return [] — and re-throw any other (genuine-bug) error.\n // Keyed on the error TYPE, not a 'not found' substring.\n try {\n transact(() => {\n result.created = editor.blocks.insertMany(seeded, flatIndex);\n });\n } catch (error) {\n if (error instanceof ToolNotFoundError) {\n return [];\n }\n throw error;\n }\n\n return result.created\n .map((block) => getById(block.id))\n .filter((node): node is BlockNode => node !== null);\n };\n\n const update = (\n id: string,\n data?: BlockToolData,\n tunes?: { [name: string]: BlockTuneData }\n ): void => {\n // Silent existence probe (NOT getBlockIndex, which warns on unknown ids).\n if (getById(id) === null) {\n return;\n }\n\n // Core update is async and forms its own undo/Yjs step, so it is NOT\n // wrapped in transact (that would close the group before the write lands).\n // Swallow any rejection so it can't surface as an unhandled rejection.\n void Promise.resolve(editor.blocks.update(id, data, tunes)).catch(() => undefined);\n };\n\n const convert = (\n id: string,\n newType: string,\n dataOverrides?: BlockToolData,\n options?: { caret?: CaretTarget }\n ): void => {\n if (getById(id) === null) {\n return;\n }\n\n // Core convert is async and rejects when a tool lacks a conversionConfig.\n // Like update, it owns its own history step (no transact). Position the\n // caret only AFTER a successful convert (matching the in-editor keyboard\n // turn-into, which preserves the caret) when the caller asked for it.\n // Swallow the rejection so a non-convertible block is a graceful no-op —\n // and on rejection the caret is left untouched.\n void Promise.resolve(editor.blocks.convert(id, newType, dataOverrides))\n .then((converted) => {\n if (options?.caret !== undefined) {\n // Core convert routes through replace(), which regenerates the block\n // id — the resolved BlockAPI carries the NEW id. Target it (falling\n // back to the original only if a faithless path resolves nothing) so\n // the caret lands in the converted block instead of a stale id.\n const targetId = converted?.id ?? id;\n\n editor.caret.setToBlock(\n targetId,\n options.caret.position ?? 'default',\n options.caret.offset ?? 0\n );\n }\n })\n .catch(() => undefined);\n };\n\n const transactWithoutCapture = (fn: () => void): void => {\n if (editor.blocks.transactWithoutCapture !== undefined) {\n editor.blocks.transactWithoutCapture(fn);\n } else {\n fn();\n }\n };\n\n const getBlocksCount = (): number => {\n onRead();\n\n return editor.blocks.getBlocksCount();\n };\n\n const getCurrentBlockIndex = (): number => {\n onRead();\n\n return editor.blocks.getCurrentBlockIndex();\n };\n\n const getBlockByIndex = (index: number): BlockNode | null => {\n onRead();\n const block = editor.blocks.getBlockByIndex(index);\n\n return block === undefined ? null : getById(block.id);\n };\n\n const getBlockByElement = (element: HTMLElement): BlockNode | null => {\n onRead();\n const block = editor.blocks.getBlockByElement(element);\n\n return block === undefined ? null : getById(block.id);\n };\n\n const composeBlockData = (toolName: string): Promise<BlockToolData> =>\n editor.blocks.composeBlockData(toolName);\n\n const getBlockData = (\n id: string\n ): { data: BlockToolData; tunes: { [name: string]: BlockTuneData } } | null => {\n // Silent existence probe via the snapshot getById (NOT editor.blocks.getById,\n // which logs a `warn` for an unknown id) so a miss is a quiet null, matching\n // getBlockIndex and the other id-taking readers.\n if (getById(id) === null) {\n return null;\n }\n\n const block = editor.blocks.getById(id);\n\n if (block === null) {\n return null;\n }\n\n // preservedData/preservedTunes are core's SYNCHRONOUS last-extracted view —\n // the same snapshot clipboard ops read. Returning it (rather than the async\n // save()) keeps this reader synchronous so a block can be read and re-inserted\n // (duplicated) inside one render/handler without the ref escape hatch.\n return { data: block.preservedData, tunes: block.preservedTunes };\n };\n\n const getBlockIndex = (id: string): number | null => {\n if (getById(id) === null) {\n // Silent existence probe (NOT editor.blocks.getBlockIndex, which warns on\n // unknown ids) so a miss is a quiet null, matching every other reader.\n return null;\n }\n\n return editor.blocks.getBlockIndex(id) ?? null;\n };\n\n const renderFromHTML = (html: string): Promise<void> => editor.blocks.renderFromHTML(html);\n\n const splitBlock = (\n currentBlockId: string,\n currentBlockData: Partial<BlockToolData>,\n newBlockType: string,\n newBlockData: BlockToolData,\n insertIndex: number\n ): BlockNode | null => {\n // Silent no-op for an unknown current block, matching every other id-taking\n // mutator. Probe via the snapshot getById (NOT getBlockIndex, which warns).\n if (getById(currentBlockId) === null) {\n return null;\n }\n\n // A negative insertIndex is malformed — core would forward it to a splice\n // (which counts from the array end) and silently split at the wrong slot.\n // Honor the silent-no-op convention instead (consistent with\n // insertOutputData's negative-index guard): return null without touching core.\n if (insertIndex < 0) {\n return null;\n }\n\n // An unknown newBlockType makes core's compose path throw a typed\n // ToolNotFoundError — honor the null contract (mirroring insert/insertTree);\n // re-throw any other (genuine-bug) error. Keyed on the error TYPE.\n const created = ((): { id: string } | null | undefined => {\n try {\n return editor.blocks.splitBlock(\n currentBlockId,\n currentBlockData,\n newBlockType,\n newBlockData,\n insertIndex\n );\n } catch (error) {\n if (error instanceof ToolNotFoundError) {\n return null;\n }\n throw error;\n }\n })();\n\n return created === undefined || created === null ? null : getById(created.id);\n };\n\n const insertOutputData = (\n blocks: OutputBlockData[],\n options?: { index?: number }\n ): BlockNode[] => {\n // An empty batch opens no transaction (no spurious undo boundary).\n if (blocks.length === 0) {\n return [];\n }\n\n // A negative index is malformed — core throws a bare validation Error. Honor\n // the silent-no-op convention instead: return [] without inserting (no\n // transaction, no surprise end-append), consistent with the rest of the API.\n if (options?.index !== undefined && options.index < 0) {\n return [];\n }\n\n // ONE transact for the whole batch → a single atomic undo step. Delegates\n // to core's raw insertMany, which honors each block's parent/content links.\n // Honor the same null/[]-on-unknown-tool contract as insertTree (core throws\n // a typed ToolNotFoundError); re-throw any other (genuine-bug) error.\n const result: { created: Array<{ id: string }> } = { created: [] };\n\n try {\n transact(() => {\n result.created =\n options?.index !== undefined\n ? editor.blocks.insertMany(blocks, options.index)\n : editor.blocks.insertMany(blocks);\n });\n } catch (error) {\n if (error instanceof ToolNotFoundError) {\n return [];\n }\n throw error;\n }\n\n return result.created\n .map((block) => getById(block.id))\n .filter((node): node is BlockNode => node !== null);\n };\n\n /**\n * Insert one child block under `parentId` at flat `insertIndex`, atomically.\n * Delegates to core's `insertInsideParent`, which groups the block creation\n * AND the parent assignment into a single undo entry itself — so this is NOT\n * wrapped in the hook's `transact` (that would be a redundant nested group).\n * A dangling parentId is a no-op (null), mirroring `insert`'s parent guard;\n * an unknown child tool throws a typed ToolNotFoundError from core's compose\n * path — honor the null contract and re-throw anything else (genuine bug).\n */\n const insertInsideParent = (\n parentId: string,\n insertIndex: number,\n childData?: BlockToolData\n ): BlockNode | null => {\n // Silent existence probe (NOT getBlockIndex, which warns on unknown ids).\n if (getById(parentId) === null) {\n return null;\n }\n\n const created = ((): { id: string } | null | undefined => {\n try {\n return editor.blocks.insertInsideParent(parentId, insertIndex, childData);\n } catch (error) {\n if (error instanceof ToolNotFoundError) {\n return null;\n }\n throw error;\n }\n })();\n\n return created === undefined || created === null ? null : getById(created.id);\n };\n\n /**\n * Replace the whole document with saved {@link OutputData} — a document-LOAD\n * primitive (clears existing content first), the counterpart of the additive\n * {@link insertOutputData}. Pure delegation to core's async `render`.\n */\n const render = (data: OutputData): Promise<void> => editor.blocks.render(data);\n\n /** Remove every block — document reset. Pure delegation to core's async `clear`. */\n const clear = (): Promise<void> => editor.blocks.clear();\n\n /**\n * Serialize the document to Markdown — the read-side twin of\n * {@link UseBlocksApi.insertMarkdown}. Pure delegation to core's async\n * `exportMarkdown` (which lazy-loads the serializer).\n */\n const exportMarkdown = (): Promise<string> => editor.blocks.exportMarkdown();\n\n /**\n * The LIVE Yjs-sync flag, read at call time (the api handle is memoized, so a\n * cached property would go stale). Pure delegation to core's read-only flag.\n */\n const isSyncingFromYjs = (): boolean => {\n onRead();\n\n return editor.blocks.isSyncingFromYjs;\n };\n\n // Every key is listed EXPLICITLY — do NOT spread `...EMPTY_API` here. The\n // return is typed `UseBlocksApi`, so an explicit list makes a forgotten live\n // wiring a COMPILE error (missing property). Spreading EMPTY_API would instead\n // backfill the missing key with its pre-ready no-op stub, silently shipping a\n // method that does nothing when the editor IS ready — a hole no key-presence\n // test can catch (the key is present, just wrong). Keep it exhaustive.\n return {\n getById,\n getChildren,\n insert,\n insertMany,\n insertTree,\n insertMarkdown,\n exportMarkdown,\n move,\n nest,\n unnest,\n remove,\n update,\n convert,\n transact,\n transactWithoutCapture,\n getBlocksCount,\n getCurrentBlockIndex,\n getBlockByIndex,\n getBlockByElement,\n getBlockData,\n getBlockIndex,\n composeBlockData,\n renderFromHTML,\n insertOutputData,\n splitBlock,\n insertInsideParent,\n render,\n clear,\n isSyncingFromYjs,\n };\n};\n","import type { ReadOnlyModeConfig } from '@bloklabs/core';\n\n/**\n * Normalized shape of the `readOnly` config option\n */\nexport interface NormalizedReadOnlyConfig {\n enabled: boolean;\n hideControls: boolean;\n}\n\n/**\n * Single source of truth for interpreting the `readOnly` config option.\n * The object form always means read-only is enabled.\n * @param value - raw `readOnly` value from BlokConfig\n */\nexport function normalizeReadOnlyConfig(value: boolean | ReadOnlyModeConfig | undefined): NormalizedReadOnlyConfig {\n if (typeof value === 'object' && value !== null) {\n return { enabled: true, hideControls: value.hideControls === true };\n }\n\n return { enabled: value === true, hideControls: false };\n}\n","/**\n * Structural deep equality for JSON-like values (Blok `OutputData`).\n *\n * Framework-agnostic: shared by the React and Angular adapters to dedupe\n * reactive `data` updates so identical content does not trigger a redundant\n * re-render that would clobber the caret/selection. Handles the value shapes\n * that appear in editor data: plain objects, arrays, and primitives (including\n * `null`/`undefined`).\n * @param a - first value to compare\n * @param b - second value to compare\n * @returns true when both values are structurally equal\n */\nexport function deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) {\n return true;\n }\n\n if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null) {\n return false;\n }\n\n const aIsArray = Array.isArray(a);\n const bIsArray = Array.isArray(b);\n\n if (aIsArray !== bIsArray) {\n return false;\n }\n\n if (aIsArray && bIsArray) {\n if (a.length !== b.length) {\n return false;\n }\n\n return a.every((item, index) => deepEqual(item, b[index]));\n }\n\n const aObj = a as Record<string, unknown>;\n const bObj = b as Record<string, unknown>;\n const aKeys = Object.keys(aObj);\n const bKeys = Object.keys(bObj);\n\n if (aKeys.length !== bKeys.length) {\n return false;\n }\n\n return aKeys.every(\n (key) => Object.prototype.hasOwnProperty.call(bObj, key) && deepEqual(aObj[key], bObj[key])\n );\n}\n","import type { LooseOutputBlockData, LooseOutputData, OutputBlockData, OutputData } from '@bloklabs/core';\n/**\n * Public utilities for working with saved editor documents (`OutputData`).\n *\n * Consumers persisting editor content need two recurring predicates that the\n * editor itself already relies on internally:\n *\n * - structural equality, to dedupe the `data → render → onSave → data` echo\n * round-trip without clobbering the caret;\n * - emptiness, to decide whether a document carries any user content\n * (placeholder states, \"save\" button gating, skipping empty submissions).\n *\n * Both accept the loose wire shape (`data: null`, `id: null`, `parent: null`,\n * `content: null`, nullish documents) so backend DTOs can be passed as-is.\n */\nimport { deepEqual } from './deep-equal';\n\n\ntype AnyOutputData = OutputData | LooseOutputData | null | undefined;\n\n/**\n * Normalizes one block from the loose wire shape into the strict saved shape.\n * The single definition of how the wire spells \"absent\": `null`/`''` ids and\n * parents, `null`/`[]` content, `null`/missing data. Shared by\n * {@link normalizeOutputBlocks} and {@link equalsOutputBlock} so a DTO and its\n * saved echo are judged under the same rules.\n * @param block - a block in either the strict or the loose wire shape\n * @returns the block in the strict saved shape\n */\nfunction normalizeOutputBlock(block: OutputBlockData | LooseOutputBlockData): OutputBlockData {\n const { id, data, parent, content, ...rest } = block;\n\n return {\n ...rest,\n ...(typeof id === 'string' && id !== '' ? { id } : {}),\n ...(typeof parent === 'string' && parent !== '' ? { parent } : {}),\n ...(Array.isArray(content) && content.length > 0 ? { content } : {}),\n data: data ?? {},\n };\n}\n\n/**\n * Compares two blocks structurally. Both sides are normalized first\n * ({@link normalizeOutputBlock}), so the loose wire spellings of \"absent\"\n * (`parent: null`, `content: null`, `data: null`) equal the saved shape that\n * omits them. The `id` participates only when BOTH blocks carry one: the editor\n * mints a fresh id whenever content arrives without one, so an id-less origin\n * document must still compare equal to its saved echo.\n *\n * Edit metadata (`lastEditedAt`/`lastEditedBy`) never participates: it records\n * WHO touched the block and WHEN, not what it says, so a document whose only\n * delta is a stamp is not a content change.\n * @param a - first block to compare\n * @param b - second block to compare\n * @returns true when the blocks are structurally equal\n */\nfunction equalsOutputBlock(\n a: OutputBlockData | LooseOutputBlockData,\n b: OutputBlockData | LooseOutputBlockData\n): boolean {\n const { id: idA, lastEditedAt: _editedAtA, lastEditedBy: _editedByA, ...restA } = normalizeOutputBlock(a);\n const { id: idB, lastEditedAt: _editedAtB, lastEditedBy: _editedByB, ...restB } = normalizeOutputBlock(b);\n\n const hasIdA = typeof idA === 'string' && idA !== '';\n const hasIdB = typeof idB === 'string' && idB !== '';\n\n if (hasIdA && hasIdB && idA !== idB) {\n return false;\n }\n\n return deepEqual(restA, restB);\n}\n\n/**\n * The tool a pristine editor seeds its first (empty) block with. An empty block\n * of this type is UI scaffolding, not user content — see\n * {@link EqualsOutputDataOptions.ignoreEmptyDefaultBlocks}.\n */\nconst DEFAULT_BLOCK_TYPE = 'paragraph';\n\n/**\n * Options for {@link equalsOutputData}.\n */\nexport interface EqualsOutputDataOptions {\n /**\n * Ignore empty default blocks on both sides before comparing. A fresh editor\n * always seeds one empty default paragraph, so a pristine document\n * (`[{ type: 'paragraph', data: { text: '' } }]`) does not content-equal a\n * saved-empty baseline (`[]`) by default. Turn this on for dirty-vs-baseline\n * checks (\"has the user actually typed anything?\"): empty blocks of the\n * default paragraph tool are dropped from both documents first, so pristine\n * scaffolding and trailing empty lines don't register as a change. Empty\n * NON-default blocks (a content-less divider, an empty image) are kept — they\n * are meaningful content.\n */\n ignoreEmptyDefaultBlocks?: boolean;\n}\n\n/**\n * True for an empty block of the default paragraph tool — the editor's own\n * scaffolding, not user content.\n * @param block - block to inspect\n * @returns true when the block is an empty default paragraph\n */\nfunction isEmptyDefaultBlock(block: OutputBlockData | LooseOutputBlockData): boolean {\n return block.type === DEFAULT_BLOCK_TYPE && isEmptyValue(block.data);\n}\n\n/**\n * Resolves the blocks to compare for a document, dropping empty default blocks\n * when {@link EqualsOutputDataOptions.ignoreEmptyDefaultBlocks} is set.\n * @param data - document whose blocks are collected\n * @param options - comparison options\n * @returns the blocks to compare\n */\nfunction comparableBlocks(\n data: AnyOutputData,\n options?: EqualsOutputDataOptions\n): Array<OutputBlockData | LooseOutputBlockData> {\n const blocks = data?.blocks ?? [];\n\n if (options?.ignoreEmptyDefaultBlocks === true) {\n return blocks.filter((block) => !isEmptyDefaultBlock(block));\n }\n\n return blocks;\n}\n\n/**\n * Structural equality for saved documents. Compares the `blocks` arrays\n * deeply; the volatile `time` and `version` envelope fields are ignored, so a\n * document round-tripped through `save()` compares equal to its echo. Block\n * ids are compared only when both sides carry one — the editor mints fresh\n * ids for id-less content, so a legacy document still equals its saved echo.\n * Edit metadata (`lastEditedAt`/`lastEditedBy`) is ignored for the same reason:\n * it records who touched a block and when, not what it says. Nullish documents\n * compare equal to `{ blocks: [] }`.\n *\n * Pass `{ ignoreEmptyDefaultBlocks: true }` for dirty-vs-baseline checks so a\n * pristine editor (one empty default paragraph) equals a saved-empty baseline —\n * see {@link EqualsOutputDataOptions}.\n * @param a - first document to compare\n * @param b - second document to compare\n * @param options - comparison options\n * @returns true when both documents hold structurally equal blocks\n */\nexport function equalsOutputData(a: AnyOutputData, b: AnyOutputData, options?: EqualsOutputDataOptions): boolean {\n const blocksA = comparableBlocks(a, options);\n const blocksB = comparableBlocks(b, options);\n\n return blocksA.length === blocksB.length && blocksA.every((block, index) => equalsOutputBlock(block, blocksB[index]));\n}\n\n/**\n * A bounded window of the editor's recently emitted `onSave` payloads, used by\n * the framework adapters to recognize controlled-`data` echoes. Deduping\n * against only the LAST emitted payload is not enough: a host that persists on\n * save and refetches can hand the adapter a STALE echo — an earlier save\n * arriving after a newer one already replaced the baseline — and re-rendering\n * it would clobber the caret and any content typed since. Matching is\n * structural ({@link equalsOutputData}), so envelopes reshaped in transit\n * (fresh `time`, stripped ids) still count as echoes.\n * @param capacity - number of payloads retained before the oldest is evicted\n * @returns the echo window\n */\nexport function createEmittedEchoWindow(capacity: number = 20): {\n /** Records a payload the editor emitted via `onSave`. */\n record(data: OutputData | LooseOutputData): void;\n /** True when the document content-equals any recorded payload. */\n matches(data: AnyOutputData): boolean;\n /** Forgets all recorded payloads (external content took over). */\n clear(): void;\n} {\n const emitted: Array<OutputData | LooseOutputData> = [];\n\n return {\n record(data: OutputData | LooseOutputData): void {\n emitted.push(data);\n if (emitted.length > capacity) {\n emitted.shift();\n }\n },\n matches(data: AnyOutputData): boolean {\n return emitted.some((payload) => equalsOutputData(payload, data));\n },\n clear(): void {\n emitted.length = 0;\n },\n };\n}\n\n/**\n * A shared, deeply frozen empty document. Consumers persisting editor content\n * repeatedly hand-write `{ blocks: [] }` for cleared/pristine baselines; this\n * is the canonical value to use instead. Frozen (blocks array included) so a\n * shared reference can never be mutated into a stale non-empty baseline.\n */\nexport const EMPTY_OUTPUT_DATA: OutputData = Object.freeze({\n // Freeze the array too, so a shared reference can't be mutated. The public\n // `blocks` type is mutable (`OutputBlockData[]`), so the frozen (readonly)\n // array is re-widened through `unknown` — runtime stays frozen.\n blocks: Object.freeze([]) as unknown as OutputBlockData[],\n});\n\n/**\n * Maps a controlled `data` value to something the editor's `render()` accepts.\n * A whole-document `null` — a controlled \"clear to empty\" — becomes\n * `{ blocks: [] }`; any real document passes through untouched.\n *\n * The framework adapters (React/Vue/Angular) route their reactive `data` path\n * through this so a `null` never reaches `render()`, whose strict guard reads\n * `data.blocks` and would throw on `null`. `undefined` (uncontrolled) is handled\n * by the adapters before this point, so it is intentionally not an input here.\n * @param data - a controlled document, or `null` for an empty document\n * @returns a document `render()` can consume\n */\nexport function toRenderableData(data: OutputData | LooseOutputData | null): OutputData | LooseOutputData {\n return data === null ? { blocks: [] } : data;\n}\n\n/**\n * Normalizes blocks from the loose wire shape into the strict saved shape at\n * the editor's input boundaries: a `null`/missing `data` becomes `{}`, a\n * `null`/empty `id` is dropped so the block factory generates a fresh one, and\n * nullish/empty hierarchy references (`parent`, `content`) are dropped so a\n * root-level, childless block is spelled the one way the editor and `save()`\n * both spell it — absent. Idempotent — strict blocks pass through unchanged\n * (shallow-copied).\n * @param blocks - blocks in either the strict or the loose wire shape\n * @returns blocks in the strict saved shape\n */\nexport function normalizeOutputBlocks(blocks: Array<OutputBlockData | LooseOutputBlockData>): OutputBlockData[] {\n return blocks.map(normalizeOutputBlock);\n}\n\n/**\n * Normalizes a whole loose wire document into the strict saved\n * {@link OutputData} shape at an input boundary. A nullish document becomes\n * `{ blocks: [] }`; `null` envelope fields (`time`/`version`) are dropped; each\n * block is passed through {@link normalizeOutputBlocks}, so `null`/missing\n * `data` becomes `{}`, `null`/empty ids are dropped for regeneration and\n * nullish/empty `parent`/`content` references are dropped as absent.\n *\n * Unlike a hand-written `blocks.map(...)` mapper, this preserves every block\n * passthrough field — `tunes`, real `parent`/`content` references, `indent`,\n * edit metadata — so a backend DTO can be turned into strict `OutputData`\n * without silently losing hierarchy or tunes. Idempotent: a strict document\n * passes through unchanged (shallow-copied).\n * @param data - a document in the strict or loose wire shape, or nullish\n * @returns the document in the strict saved shape\n */\nexport function normalizeOutputData(data: AnyOutputData): OutputData {\n if (data === null || data === undefined) {\n return { blocks: [] };\n }\n\n return {\n ...(typeof data.version === 'string' ? { version: data.version } : {}),\n ...(typeof data.time === 'number' ? { time: data.time } : {}),\n blocks: normalizeOutputBlocks(data.blocks),\n };\n}\n\n/**\n * True when the value carries no user content: blank/whitespace-only strings,\n * empty arrays, plain objects whose values are all empty, and nullish values.\n * Numbers and booleans are presentation metadata (`level`, `checked`, styles)\n * and never count as content on their own.\n * @param value - block data value to inspect\n * @returns true when the value carries no user content\n */\nfunction isEmptyValue(value: unknown): boolean {\n if (value === null || value === undefined) {\n return true;\n }\n\n if (typeof value === 'string') {\n return value.trim() === '';\n }\n\n if (Array.isArray(value)) {\n return value.every(isEmptyValue);\n }\n\n if (typeof value === 'object') {\n return Object.values(value).every(isEmptyValue);\n }\n\n // Numbers, booleans and other primitives are metadata, not content.\n return true;\n}\n\n/**\n * True when the document carries no user content: it is nullish, has no\n * blocks, or every block's data holds only empty values (see\n * {@link isEmptyValue}). Note that content-less visual blocks (e.g. a divider,\n * whose data is `{}`) count as empty — check `blocks.length` when mere block\n * presence matters.\n * @param data - document to inspect\n * @returns true when the document carries no user content\n */\nexport function isEmptyOutputData(data: AnyOutputData): boolean {\n const blocks = data?.blocks ?? [];\n\n return blocks.every((block) => isEmptyValue(block.data));\n}\n","// src/shared/prop-schema.ts\n\n/** One field of a block's prop schema. */\nexport interface PropSchemaEntry {\n /** Default value, used when the incoming data omits this key. */\n default: unknown;\n /** Optional allowed values (advisory; not enforced at runtime in v1). */\n values?: readonly unknown[];\n}\n\n/**\n * Declarative data shape. The keys here are EXACTLY the keys `save()` returns to\n * Yjs — this closes the per-key-sync key-resurrection gap (a cleared field is\n * written as its explicit default, never dropped).\n */\nexport type PropSchema = Record<string, PropSchemaEntry>;\n\n/**\n * Fill a data object against the schema: every schema key present, incoming\n * value when defined else the schema default, and ONLY schema keys (so `save()`\n * is never partial). Returns a frozen plain object — safe to hand straight to\n * core's per-key Yjs sync.\n */\nexport const fillDefaults = <Data>(\n schema: PropSchema,\n data: Record<string, unknown>\n): Readonly<Data> => {\n const result: Record<string, unknown> = {};\n\n for (const key of Object.keys(schema)) {\n result[key] = data[key] !== undefined ? data[key] : schema[key].default;\n }\n\n return Object.freeze(result) as Readonly<Data>;\n};\n","/**\n * Centralized data attributes used across the Blok editor.\n * This is the single source of truth for all data-blok-* attributes.\n *\n * Exported as Blok.DATA_ATTR for users.\n *\n * Naming convention:\n * - Remove 'data-blok-' prefix and convert to camelCase\n * - Global attributes: hidden, disabled, focused\n * - Component prefixed: popover, popoverItem, toolbar, etc.\n */\nexport const DATA_ATTR = {\n // ============================================\n // Core Element Identifiers\n // ============================================\n\n /** Interface type identifier (blok, inline-toolbar, tooltip) */\n interface: 'data-blok-interface',\n /** Block element wrapper */\n element: 'data-blok-element',\n /** Block element content wrapper */\n elementContent: 'data-blok-element-content',\n /** Editor wrapper container */\n editor: 'data-blok-editor',\n /** Per-instance discriminator on the editor wrapper (a monotonic counter, as a\n * string). Two editors on one page share every other scope attribute, so this\n * is what lets a page-level stylesheet — Blok's own injected `style.fontSize`\n * sheet, or a host rule — address ONE editor. Public styling hook. */\n instance: 'data-blok-instance',\n /** Redactor zone */\n redactor: 'data-blok-redactor',\n /** Present on the editor wrapper once a `blocks.render()` batch has finished\n * inserting blocks into the DOM; removed while a re-render is in flight.\n * Acts as a stable render-readiness gate for consumers (e.g. E2E waits). */\n rendered: 'data-blok-rendered',\n /** Blok version number stamped on the editor wrapper (e.g. '1.10.0', 'dev').\n * Consumed by browser extensions to identify the running version. */\n version: 'data-blok-version',\n\n // ============================================\n // Block Identifiers\n // ============================================\n\n /** Block unique identifier */\n id: 'data-blok-id',\n /** Block component/tool type */\n component: 'data-blok-component',\n /** Tool type attribute */\n tool: 'data-blok-tool',\n /** Block nesting depth (derived from the parentId chain) */\n depth: 'data-blok-depth',\n /** Flat list-nesting indentation level (0 = root); tool-agnostic, mirrors list depth */\n indent: 'data-blok-indent',\n /** Header tool's heading level (1-6). Public styling hook — keyed by level rather\n * than by tag name, so a level remapped to a custom tag via `levelOverrides[n].tag`\n * (types/tools/header.d.ts) still matches its level's typography rules. */\n headingLevel: 'data-blok-heading-level',\n\n // ============================================\n // Global States\n // ============================================\n\n /** Element is hidden from view */\n hidden: 'data-blok-hidden',\n /** Element is disabled and non-interactive */\n disabled: 'data-blok-disabled',\n /** Element is focused via keyboard navigation */\n focused: 'data-blok-focused',\n /** Block is selected */\n selected: 'data-blok-selected',\n /** Block is stretched */\n stretched: 'data-blok-stretched',\n /** Editor or element is empty */\n empty: 'data-blok-empty',\n /** Present on the editor wrapper while read-only mode is active.\n * Public styling hook — lets hosts key rules off the editing state\n * without JS. Deliberately does NOT collapse the gutter: plain\n * read-only still shows the block-hover copy-link control there, and\n * in-place readOnly.set() flips must not shift the layout. */\n readonly: 'data-blok-readonly',\n /** Present on the editor wrapper while read-only mode hides ALL editor\n * controls (readOnly: { hideControls: true }). Public styling hook —\n * drives the gutter auto-collapse for genuinely chromeless read-only. */\n controlsHidden: 'data-blok-controls-hidden',\n /** Present on the editor wrapper when config.hideToolbar is true.\n * Public styling hook — drives the gutter auto-collapse (the gutter\n * exists solely to house the toolbar's +/⠿ controls). */\n toolbarHidden: 'data-blok-toolbar-hidden',\n /** Which gutter the floating block controls occupy: 'left' (default,\n * inline-start) or 'right' (inline-end). Written on the editor wrapper from\n * config.toolbarPosition and kept in sync by `toolbar.setPosition()`.\n * Public styling hook — drives the gutter swap and the actions-bar side. */\n toolbarPosition: 'data-blok-toolbar-position',\n\n // ============================================\n // Editor Modes\n // ============================================\n\n /** Content alignment mode (left, center, right) */\n contentAlign: 'data-blok-content-align',\n /** Right-to-left mode */\n rtl: 'data-blok-rtl',\n /** Editor content width mode (present with value \"full\" for wide mode; absent = narrow) */\n width: 'data-blok-width',\n /** Present on the editor wrapper when config.style.nativeSelection is true.\n * Public styling hook — disables Blok's ::selection repaint (preflight.css)\n * and re-points the fake-background highlight at the UA Highlight color\n * (colors.css), so selection falls back to native/host-defined colors. */\n nativeSelection: 'data-blok-native-selection',\n /** Present on the editor wrapper while a cross-block TEXT selection is painted.\n * Suppresses the engine's own ::selection paint (main.css) so the\n * ::highlight() sub-ranges are the only thing drawn — Chromium and Firefox\n * paint such a range natively too and would otherwise double it up. */\n crossSelection: 'data-blok-cross-selection',\n\n // ============================================\n // Drag and Drop\n // ============================================\n\n /** Block is being dragged */\n dragging: 'data-blok-dragging',\n /** Multiple blocks being dragged */\n draggingMulti: 'data-blok-dragging-multi',\n /** Block is being duplicated (Alt+drag) */\n duplicating: 'data-blok-duplicating',\n /** Drag handle element */\n dragHandle: 'data-blok-drag-handle',\n\n // ============================================\n // Toolbar\n // ============================================\n\n /** Toolbar element */\n toolbar: 'data-blok-toolbar',\n /** The floating block-controls bar (plus button + drag/settings handle)\n * inside the toolbar. Public styling hook — the side it docks to is driven\n * from the wrapper's `data-blok-toolbar-position`. */\n toolbarActions: 'data-blok-toolbar-actions',\n /** Settings toggler button */\n settingsToggler: 'data-blok-settings-toggler',\n /** Toolbox is open */\n toolboxOpened: 'data-blok-toolbox-opened',\n /** Block settings is open */\n blockSettingsOpened: 'data-blok-block-settings-opened',\n /** Element is opened (generic) */\n opened: 'data-blok-opened',\n\n // ============================================\n // Popover Container\n // ============================================\n\n /** Root popover element */\n popover: 'data-blok-popover',\n /** Popover container wrapper */\n popoverContainer: 'data-blok-popover-container',\n /** Popover items list */\n popoverItems: 'data-blok-popover-items',\n /** Custom, engine-independent scrollbar thumb overlaid on the popover items */\n popoverScrollbar: 'data-blok-popover-scrollbar',\n /** Stamped on the custom scrollbar thumb while it is being dragged (keeps it revealed) */\n popoverScrollbarDragging: 'data-blok-dragging',\n /** Stamped on a scroll container while it is actively scrolling (reveals the auto-hidden scrollbar thumb) */\n scrolling: 'data-blok-scrolling',\n /** Popover overlay element */\n popoverOverlay: 'data-blok-popover-overlay',\n /** Popover custom content area */\n popoverCustomContent: 'data-blok-popover-custom-content',\n /** Popover custom class */\n popoverCustomClass: 'data-blok-popover-custom-class',\n /** Inline popover variant */\n popoverInline: 'data-blok-popover-inline',\n /** Popover is open */\n popoverOpened: 'data-blok-popover-opened',\n /** Popover opens upward */\n popoverOpenTop: 'data-blok-popover-open-top',\n /** Popover opens leftward */\n popoverOpenLeft: 'data-blok-popover-open-left',\n\n // ============================================\n // Popover Nesting\n // ============================================\n\n /** Nested popover indicator */\n nested: 'data-blok-nested',\n /** Nesting level value */\n nestedLevel: 'data-blok-nested-level',\n /** Group label for promoted search results from nested children */\n promotedGroupLabel: 'data-blok-promoted-group-label',\n /** Group label for top-level matches in search results */\n topLevelGroupLabel: 'data-blok-top-level-group-label',\n\n // ============================================\n // Popover Header\n // ============================================\n\n /** Header container */\n popoverHeader: 'data-blok-popover-header',\n /** Header text element */\n popoverHeaderText: 'data-blok-popover-header-text',\n /** Back button in nested popover */\n popoverHeaderBackButton: 'data-blok-popover-header-back-button',\n\n // ============================================\n // Popover Items\n // ============================================\n\n /** Item container */\n popoverItem: 'data-blok-popover-item',\n /** Item icon wrapper */\n popoverItemIcon: 'data-blok-popover-item-icon',\n /** Chevron icon for nested items */\n popoverItemIconChevronRight: 'data-blok-popover-item-icon-chevron-right',\n /** Item title text */\n popoverItemTitle: 'data-blok-popover-item-title',\n /** Item secondary title */\n popoverItemSecondaryTitle: 'data-blok-popover-item-secondary-title',\n /** Item is active/selected */\n popoverItemActive: 'data-blok-popover-item-active',\n /** Item's child menu is currently open — keeps the trigger looking selected */\n popoverItemChildrenOpen: 'data-blok-popover-item-children-open',\n /** Confirmation state */\n popoverItemConfirmation: 'data-blok-popover-item-confirmation',\n /** Disable hover styling */\n popoverItemNoHover: 'data-blok-popover-item-no-hover',\n /** Disable focus handling */\n popoverItemNoFocus: 'data-blok-popover-item-no-focus',\n /** Destructive action item (e.g. delete) */\n popoverItemDestructive: 'data-blok-popover-item-destructive',\n /** Separator item */\n popoverItemSeparator: 'data-blok-popover-item-separator',\n /** Separator line element */\n popoverItemSeparatorLine: 'data-blok-popover-item-separator-line',\n /** HTML-based item */\n popoverItemHtml: 'data-blok-popover-item-html',\n /** Item has child menu */\n hasChildren: 'data-blok-has-children',\n /** Item name identifier */\n itemName: 'data-blok-item-name',\n /** No search results shown */\n nothingFoundDisplayed: 'data-blok-nothing-found-displayed',\n\n // ============================================\n // Overlay / Selection\n // ============================================\n\n /** Selection overlay */\n overlay: 'data-blok-overlay',\n /** Overlay container */\n overlayContainer: 'data-blok-overlay-container',\n /** Selection rectangle */\n overlayRectangle: 'data-blok-overlay-rectangle',\n /** Overlay is hidden */\n overlayHidden: 'data-blok-overlay-hidden',\n /** Fake cursor indicator */\n fakeCursor: 'data-blok-fake-cursor',\n /** Fake background for selection */\n fakeBackground: 'data-blok-fake-background',\n\n // ============================================\n // Scroll\n // ============================================\n\n /** Auto-scroll zone (top/bottom) */\n scrollZone: 'data-blok-scroll-zone',\n /** Scroll is locked */\n scrollLocked: 'data-blok-scroll-locked',\n /** Hard scroll lock */\n scrollLockedHard: 'data-blok-scroll-locked-hard',\n\n // ============================================\n // Caret\n // ============================================\n\n /** Shadow caret element */\n shadowCaret: 'data-blok-shadow-caret',\n\n // ============================================\n // Placeholders\n // ============================================\n\n /** Placeholder text */\n placeholder: 'data-blok-placeholder',\n /** Active placeholder text */\n placeholderActive: 'data-blok-placeholder-active',\n\n // ============================================\n // Columns Layout\n // ============================================\n\n /** The columns row rendered by the column_list tool (the flex container).\n * Public styling hook — its direct `[data-blok-element]` children are the\n * column holders, whose shrink floor reads `--blok-column-min-width` and\n * whose gutter reads `--blok-column-gutter`. */\n columns: 'data-blok-columns',\n /** A single column inside a columns row. */\n column: 'data-blok-column',\n /** Drag-to-resize separator between two adjacent columns. Present only in\n * edit mode — the separators ARE the gutter there. */\n columnResizer: 'data-blok-column-resizer',\n /** Present on a columns row whose gutter comes from the container's own\n * column-gap instead of from resizer elements. Set in read-only mode, where\n * no resizers are built — the discriminator between an editable row and a\n * published one. */\n columnsStaticGutter: 'data-blok-columns-static-gutter',\n\n // ============================================\n // Nested Blocks\n // ============================================\n\n /** Container that hosts nested block holders (table cells, toggle/callout/header children).\n * Used as a universal guard: before moving a block holder via appendChild,\n * check `holder.closest([nestedBlocks])` — if truthy, the holder is already\n * claimed by another container and must not be stolen. */\n nestedBlocks: 'data-blok-nested-blocks',\n\n // ============================================\n // Mutation Tracking\n // ============================================\n\n /** Element excluded from mutation tracking */\n mutationFree: 'data-blok-mutation-free',\n\n // ============================================\n // Keyboard Ownership\n // ============================================\n\n /** Marks a subtree whose keyboard belongs to the Tool that rendered it, not to\n * the editor. Blok's block-level keydown/keyup handling stands down entirely\n * for events originating inside it — Escape, Tab, the arrows, \"/\" and the\n * Enter/Backspace/Delete structural keys all reach the element untouched.\n *\n * Blok already exempts native `<input>`/`<textarea>` from the STRUCTURAL keys\n * (Enter/Backspace/Delete and \"/\") because those are contenteditable-shaped\n * and would splice the document around a form field. Escape/Tab/arrows are\n * deliberately NOT exempt — they are how a user leaves a field. That default\n * is right for a one-line title input and wrong for a field with its own\n * keyboard semantics (Tab between sub-fields, Escape to cancel an edit, arrows\n * to walk a suggestion list), which is exactly what this attribute is for.\n * Public authoring hook. */\n keyboardOwner: 'data-blok-keyboard-owner',\n\n // ============================================\n // Navigation\n // ============================================\n\n /** Block has navigation focus */\n navigationFocused: 'data-blok-navigation-focused',\n /** Flipper navigation target */\n flipperNavigationTarget: 'data-blok-flipper-navigation-target',\n\n // ============================================\n // Inline Toolbar\n // ============================================\n\n /** Inline toolbar enabled on external element */\n inlineToolbar: 'data-blok-inline-toolbar',\n\n // ============================================\n // Link Tool\n // ============================================\n\n /** Link tool is active */\n linkToolActive: 'data-blok-link-tool-active',\n /** Link tool unlink mode */\n linkToolUnlink: 'data-blok-link-tool-unlink',\n /** Link tool input is opened */\n linkToolInputOpened: 'data-blok-link-tool-input-opened',\n\n // ============================================\n // Bold Tool\n // ============================================\n\n /** Bold collapsed length tracking */\n boldCollapsedLength: 'data-blok-bold-collapsed-length',\n /** Bold collapsed active state */\n boldCollapsedActive: 'data-blok-bold-collapsed-active',\n /** Bold previous length tracking */\n boldPrevLength: 'data-blok-bold-prev-length',\n /** Bold leading whitespace */\n boldLeadingWs: 'data-blok-bold-leading-ws',\n /** Bold marker */\n boldMarker: 'data-blok-bold-marker',\n\n // ============================================\n // Tooltip\n // ============================================\n\n /** Tooltip is shown */\n shown: 'data-blok-shown',\n /** Tooltip placement */\n placement: 'data-blok-placement',\n\n // ============================================\n // Notifier\n // ============================================\n\n /** Bounce in animation */\n bounceIn: 'data-blok-bounce-in',\n\n // ============================================\n // Announcer (Accessibility)\n // ============================================\n\n /** Live region announcer */\n announcer: 'data-blok-announcer',\n\n // ============================================\n // Stub Block\n // ============================================\n\n /** Stub block element */\n stub: 'data-blok-stub',\n /** Stub info section */\n stubInfo: 'data-blok-stub-info',\n /** Stub title */\n stubTitle: 'data-blok-stub-title',\n /** Stub subtitle */\n stubSubtitle: 'data-blok-stub-subtitle',\n\n // ============================================\n // Slash Search\n // ============================================\n\n /** Slash search active on content editable */\n slashSearch: 'data-blok-slash-search',\n\n // ============================================\n // Testing\n // ============================================\n\n /** Test identifier (for E2E tests) */\n testid: 'data-blok-testid',\n /** Force hover state (for tests/storybook) */\n forceHover: 'data-blok-force-hover',\n} as const;\n\n/**\n * Type for DATA_ATTR keys\n */\nexport type DataAttrKey = keyof typeof DATA_ATTR;\n\n/**\n * Type for DATA_ATTR values\n */\nexport type DataAttrValue = (typeof DATA_ATTR)[DataAttrKey];\n\n/**\n * Helper function to create a CSS selector from an attribute\n *\n * @param attr - The data attribute name from DATA_ATTR\n * @param value - Optional value for the attribute (defaults to presence selector)\n * @returns CSS selector string\n *\n * @example\n * createSelector(DATA_ATTR.element) // '[data-blok-element]'\n * createSelector(DATA_ATTR.selected, true) // '[data-blok-selected=\"true\"]'\n * createSelector(DATA_ATTR.tool, 'paragraph') // '[data-blok-tool=\"paragraph\"]'\n */\nexport const createSelector = (attr: DataAttrValue, value?: string | boolean): string => {\n if (value === undefined) {\n return `[${attr}]`;\n }\n\n return `[${attr}=\"${value}\"]`;\n};\n","/**\n * HTML manipulation utilities\n */\n\n/**\n * Strips fake background wrapper elements from HTML content.\n * These elements are used by the inline toolbar for visual selection highlighting\n * and should not be persisted in saved data.\n * @param html - HTML content that may contain fake background elements\n * @returns HTML content with fake background wrappers removed but their content preserved\n */\nexport const stripFakeBackgroundElements = (html: string): string => {\n if (!html || !html.includes('data-blok-fake-background')) {\n return html;\n }\n\n const tempDiv = document.createElement('div');\n\n tempDiv.innerHTML = html;\n\n const fakeBackgrounds = tempDiv.querySelectorAll('[data-blok-fake-background=\"true\"]');\n\n fakeBackgrounds.forEach((element) => {\n const parent = element.parentNode;\n\n if (!parent) {\n return;\n }\n\n while (element.firstChild) {\n parent.insertBefore(element.firstChild, element);\n }\n\n parent.removeChild(element);\n });\n\n return tempDiv.innerHTML;\n};\n\n/**\n * An intersection rather than `interface extends Element`: TypeScript 6's\n * lib.dom.d.ts declares `moveBefore` as a required member of ParentNode, and an\n * interface may not redeclare an inherited member as optional. Intersections\n * skip that declaration-compatibility check, so this compiles on both the 5.9\n * libs (no `moveBefore` at all) and the 6.0 libs (required `moveBefore`).\n */\ntype StatefulMoveParent = Element & {\n moveBefore?(node: Node, reference: Node | null): void;\n};\n\n/**\n * Repositions an already-attached node within `parent`, inserting it before\n * `reference` (or at the end when `reference` is null), while preserving the\n * node's live state — an iframe keeps its loaded document, media keeps playing,\n * form fields keep focus and value.\n *\n * A plain insertBefore/appendChild detaches and re-attaches the node, which\n * resets exactly that state (re-parented iframes reload). The browser's\n * state-preserving move (`moveBefore`, Chrome 133+) avoids the detach; we fall\n * back to insertBefore where it is unavailable or throws (e.g. cross-document\n * moves, or a node that is not connected).\n */\nconst statefulMove = (parent: StatefulMoveParent, node: Node, reference: Node | null): void => {\n if (reference === node) {\n return;\n }\n\n if (typeof parent.moveBefore === 'function' && node.isConnected && parent.isConnected) {\n try {\n parent.moveBefore(node, reference);\n\n return;\n } catch {\n // moveBefore enforces stricter invariants than insertBefore (same\n // document, connected node); fall back to a plain, state-resetting insert.\n }\n }\n\n parent.insertBefore(node, reference);\n};\n\n/**\n * Moves `node` to sit immediately before `reference`, preserving live state.\n * @see statefulMove\n */\nexport const moveElementBefore = (node: Node, reference: Element): void => {\n const parent = reference.parentNode;\n\n if (parent instanceof Element) {\n statefulMove(parent, node, reference);\n }\n};\n\n/**\n * Moves `node` to sit immediately after `reference`, preserving live state.\n * @see statefulMove\n */\nexport const moveElementAfter = (node: Node, reference: Element): void => {\n const parent = reference.parentNode;\n\n if (parent instanceof Element) {\n statefulMove(parent, node, reference.nextSibling);\n }\n};\n\n/**\n * Moves `node` to the end of `parent`'s children, preserving live state.\n * @see statefulMove\n */\nexport const moveElementToEnd = (parent: Element, node: Node): void => {\n statefulMove(parent, node, null);\n};\n","import { DATA_ATTR } from '../components/constants/data-attributes';\nimport { moveElementBefore, moveElementToEnd } from '../components/utils/html';\n\n/**\n * The caret, captured as raw primitives.\n *\n * A Range cannot stand in for this: every Range is LIVE, so the removal a\n * non-preserving move performs relocates its boundary points out of the moved\n * subtree before they could be re-applied. The (node, offset) pairs read out\n * beforehand are the only thing that survives.\n */\ninterface CaretSnapshot {\n /** The focused element, when it sits inside the holder being moved. */\n focused: HTMLElement | null;\n /** Range start, when the range sits inside the holder being moved. */\n start: [Node, number] | null;\n /** Range end, matching {@link CaretSnapshot.start}. */\n end: [Node, number] | null;\n}\n\n/**\n * Captures focus + caret, but only the part of it that lives inside `holder` —\n * a selection anywhere else is none of this move's business and must be left\n * exactly as it is.\n * @param holder - the holder about to be moved\n * @returns the snapshot, or null when the caret is elsewhere\n */\nconst captureCaretWithin = (holder: HTMLElement): CaretSnapshot | null => {\n const ownerDocument = holder.ownerDocument;\n const activeElement = ownerDocument.activeElement;\n const focused =\n activeElement instanceof HTMLElement && holder.contains(activeElement) ? activeElement : null;\n\n const selection = ownerDocument.defaultView?.getSelection() ?? null;\n const range = selection !== null && selection.rangeCount > 0 ? selection.getRangeAt(0) : null;\n const rangeInside =\n range !== null && holder.contains(range.startContainer) && holder.contains(range.endContainer);\n\n if (focused === null && !rangeInside) {\n return null;\n }\n\n return {\n focused,\n start: rangeInside && range !== null ? [range.startContainer, range.startOffset] : null,\n end: rangeInside && range !== null ? [range.endContainer, range.endOffset] : null,\n };\n};\n\n/**\n * Re-applies a snapshot, but only where the move actually destroyed it —\n * a browser with the state-preserving move keeps focus and the caret itself,\n * and re-setting an identical range there would emit a spurious\n * `selectionchange` at every container render.\n * @param snapshot - what {@link captureCaretWithin} read, or null\n */\nconst restoreCaret = (snapshot: CaretSnapshot | null): void => {\n if (snapshot === null) {\n return;\n }\n\n const { focused, start, end } = snapshot;\n\n if (focused !== null && focused.isConnected && focused.ownerDocument.activeElement !== focused) {\n focused.focus({ preventScroll: true });\n }\n\n if (start === null || end === null || !start[0].isConnected) {\n return;\n }\n\n const ownerDocument = start[0].ownerDocument;\n const selection = ownerDocument?.defaultView?.getSelection() ?? null;\n\n if (ownerDocument === null || selection === null) {\n return;\n }\n\n const live = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;\n const intact =\n live !== null &&\n live.startContainer === start[0] &&\n live.startOffset === start[1] &&\n live.endContainer === end[0] &&\n live.endOffset === end[1];\n\n if (intact) {\n return;\n }\n\n const range = ownerDocument.createRange();\n\n range.setStart(start[0], start[1]);\n range.setEnd(end[0], end[1]);\n selection.removeAllRanges();\n selection.addRange(range);\n};\n\n/**\n * Mount child block holders into a container, skipping children that are\n * already in place or claimed by another nested-blocks container.\n *\n * Used by toggle, header, column, and callout tools — and by the React, Vue and\n * Angular block adapters — to reconcile child holders during the `rendered()`\n * lifecycle hook. It is the standing DOM↔model reconciler for container blocks:\n * safe to call on every render, and the only thing that heals a child holder\n * that core parked outside the container while the container's own slot had not\n * been created yet.\n * @param container - the container element child holders belong in; usually the\n * element carrying `data-blok-nested-blocks`.\n * @param children - the container block's MODEL children, in model order (e.g.\n * `api.blocks.getChildren(blockId)`).\n */\nexport const mountChildBlocks = (\n container: HTMLElement,\n children: { holder: HTMLElement }[],\n): void => {\n /**\n * Places a holder at its MODEL position: before the first later child that is\n * already mounted here, or at the end when there is none. A plain appendChild\n * would put a reclaimed middle child last — children [A, B, C] with only B\n * stranded would render A, C, B.\n *\n * The move goes through the state-preserving helpers rather than raw\n * insertBefore/appendChild: re-parenting a live node runs the DOM removing\n * steps, which blur the focused contenteditable and relocate every live Range\n * out of the moved subtree — the user's caret vanishes to <body> mid-typing.\n * Where the browser has no state-preserving move, the caret is put back by\n * hand around the move.\n * @param holder - the holder to mount\n * @param index - the holder's position in `children`\n */\n const mountAtModelPosition = (holder: HTMLElement, index: number): void => {\n const anchor = children\n .slice(index + 1)\n .find(next => next.holder.parentElement === container)?.holder ?? null;\n\n const caret = captureCaretWithin(holder);\n\n anchor !== null ? moveElementBefore(holder, anchor) : moveElementToEnd(container, holder);\n\n restoreCaret(caret);\n };\n\n for (const [index, child] of children.entries()) {\n if (child.holder.parentElement === container) {\n continue;\n }\n\n const nested = child.holder.closest(`[${DATA_ATTR.nestedBlocks}]`);\n\n // Claim a holder stranded in an ANCESTOR nested container. Callers pass\n // this container's own MODEL children, and a container that ENCLOSES this\n // one can never be a legitimate home for them — that is model/DOM\n // divergence by definition. Two ways to get there: a drag reparent into a\n // column drops the moved holder directly into the [data-blok-columns] row\n // (where it renders as a rogue extra column), and a newly inserted first\n // child is anchored as the container block's DOM *sibling*, i.e. inside\n // whatever nested container encloses it — permanent when the destination\n // slot had not committed yet (a framework adapter's portal commits a render\n // later than core inserts), because nothing else ever re-runs the mount.\n if (nested !== null && nested !== container && nested.contains(container)) {\n mountAtModelPosition(child.holder, index);\n continue;\n }\n\n // Otherwise leave holders that already live inside another nested container\n // (a sibling, or a deeper nesting within this one) where they are.\n if (nested !== null) {\n continue;\n }\n\n mountAtModelPosition(child.holder, index);\n }\n};\n","import { DATA_ATTR } from '../components/constants/data-attributes';\n\n/**\n * One child's decoration: attribute name → value. `null`/`undefined` removes the\n * attribute; a boolean or number is stringified (so `false` writes\n * `data-active=\"false\"`, which CSS can select, rather than dropping the hook).\n */\nexport type ChildAttributes = Record<string, string | number | boolean | null | undefined>;\n\n/** The minimum a child must expose for a decoration pass. */\nexport interface DecoratableChild {\n id: string;\n holder: HTMLElement;\n}\n\n/**\n * A per-child decorator: what to write for the child at `index`.\n *\n * Generic over the child so an adapter can declare its decorators in terms of the\n * full `BlockAPI` its authors receive. A non-generic `(child: DecoratableChild)`\n * parameter would REJECT those: a function that demands a full BlockAPI is not\n * assignable to one promising to accept the structural minimum.\n */\nexport type ChildAttributesFn<Child extends DecoratableChild = DecoratableChild> = (\n child: Child,\n index: number\n) => ChildAttributes;\n\n/** What the previous decoration pass wrote for one child, so it can be undone. */\ninterface StampedChild {\n /** The element written to — a holder for one ledger, a content wrapper for the other. */\n target: HTMLElement;\n names: string[];\n}\n\n/** The ledgers a container keeps between passes; create one per child slot. */\nexport interface ChildDecorationLedger {\n holders: Map<string, StampedChild>;\n contents: Map<string, StampedChild>;\n}\n\n/**\n * A fresh pair of ledgers for one container's child slot.\n * @returns empty holder/content ledgers\n */\nexport const createChildDecorationLedger = (): ChildDecorationLedger => ({\n holders: new Map(),\n contents: new Map(),\n});\n\n/**\n * The child's OWN content wrapper, or null when its DOM has not committed yet.\n *\n * The first `[data-blok-element-content]` in document order under a holder is\n * always that block's own: a descendant block's wrapper necessarily sits INSIDE\n * it. Not `firstElementChild` — block tunes wrap the content node, so it is not\n * reliably a direct child (this is the same lookup core's own\n * `refreshToolRootElement` uses).\n * @param holder - the child block's holder\n * @returns the content wrapper, or null\n */\nconst contentWrapperOf = (holder: HTMLElement): HTMLElement | null =>\n holder.querySelector<HTMLElement>(`[${DATA_ATTR.elementContent}]`);\n\n/**\n * Apply one decoration pass and clear the previous pass's leftovers — including\n * on a child that has since left the container, which would otherwise keep a\n * dead index forever.\n * @param ledger - what the last pass wrote (mutated)\n * @param children - the container's model children, in model order\n * @param decorate - the per-child decorator for the child HOLDERS, if any\n * @param resolveTarget - which element of a child this pass writes to\n */\nconst applyPass = <Child extends DecoratableChild>(\n ledger: Map<string, StampedChild>,\n children: Child[],\n decorate: ChildAttributesFn<Child> | undefined,\n resolveTarget: (holder: HTMLElement) => HTMLElement | null\n): void => {\n const next = new Map<string, StampedChild>();\n\n children.forEach((child, index) => {\n const target = resolveTarget(child.holder);\n\n /**\n * A portal-rendered child commits its DOM a frame after core inserts it, so\n * its content wrapper can legitimately be missing on this pass. Skipping\n * (rather than throwing) leaves the next pass to stamp it.\n */\n if (target === null) {\n return;\n }\n\n const names: string[] = [];\n\n for (const [name, value] of Object.entries(decorate?.(child, index) ?? {})) {\n if (value === null || value === undefined) {\n target.removeAttribute(name);\n continue;\n }\n\n target.setAttribute(name, String(value));\n names.push(name);\n }\n\n next.set(child.id, { target, names });\n });\n\n for (const [id, previous] of ledger) {\n const current = next.get(id);\n\n previous.names\n .filter(name => current === undefined || !current.names.includes(name))\n .forEach(name => previous.target.removeAttribute(name));\n }\n\n ledger.clear();\n next.forEach((entry, id) => ledger.set(id, entry));\n};\n\n/**\n * Decorate a container's children: named attributes on each child's HOLDER and,\n * separately, on each child's `[data-blok-element-content]` wrapper.\n *\n * The single implementation behind the React, Vue and Angular per-child\n * decoration channels, so the three cannot drift on which element a hook lands\n * on or on when a dropped hook is cleaned up.\n *\n * BOTH levels exist because core's child-holder decoration law blesses both, and\n * a container needs both: the holder is the child's outer box (rails, indices,\n * hover states), while the content wrapper is where the child's own text box\n * begins — which is what a numbered rail or a connector line has to align to.\n * With only the holder reachable, a container had to encode core's wrapper chain\n * in its own CSS (`[data-step] > [data-blok-element-content] > …`) and broke\n * whenever that chain changed. Neither hook may introduce an element: holders\n * stay DIRECT children of the slot because core's reparenting and caret\n * sibling checks compare `holder.parentElement` by identity.\n *\n * Both are inert with respect to change tracking: core's mutation filter drops a\n * holder- or content-targeted attribute record for the CHILD block (both are\n * ancestors of the child's tool element, not descendants) and scores it\n * mutation-free for the CONTAINER (whose own `data-blok-mutation-free` host is\n * the nearest such ancestor).\n * @param ledger - the slot's ledgers from {@link createChildDecorationLedger}\n * @param children - the container's model children, in model order\n * @param decorators - the authored per-child decorators\n * @param decorators.childAttributes - written on each child's holder\n * @param decorators.childContentAttributes - written on each child's content wrapper\n */\nexport const applyChildDecoration = <Child extends DecoratableChild>(\n ledger: ChildDecorationLedger,\n children: Child[],\n decorators: {\n childAttributes?: ChildAttributesFn<Child>;\n childContentAttributes?: ChildAttributesFn<Child>;\n }\n): void => {\n applyPass(ledger.holders, children, decorators.childAttributes, holder => holder);\n applyPass(ledger.contents, children, decorators.childContentAttributes, contentWrapperOf);\n};\n","export type { BlockChildrenMountedPayload } from '@bloklabs/core';\n\n/**\n * Fired when a CONTAINER block's child holders have been mounted into its\n * child slot — the moment the child DOM has settled and a caret set into a\n * freshly inserted child sticks.\n *\n * Emitted by the React, Vue and Angular block adapters, whose portals commit a\n * frame AFTER core's `rendered()` hook; a vanilla container tool mounts its\n * children synchronously inside `rendered()`, so for those `block:rendered`\n * already means \"settled\". It fires on every reconciliation pass of the slot,\n * not only the first, so treat it as a settle signal rather than a change\n * signal.\n *\n * Public event name: `block:childrenMounted`.\n */\nexport const BlockChildrenMounted = 'block:childrenMounted';\n","import {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n Input,\n NgZone,\n Output,\n ViewChild,\n computed,\n effect,\n forwardRef,\n inject,\n signal,\n type AfterViewInit,\n type DoCheck,\n} from '@angular/core';\nimport { NG_VALUE_ACCESSOR, type ControlValueAccessor } from '@angular/forms';\nimport { BlokContentDirective } from './blok-content.directive';\nimport { BLOK_DEFAULT_CONFIG } from './provide-blok';\nimport { deepEqual } from '../adapters-contract';\nimport { equalsOutputData } from '../adapters-contract';\nimport { normalizeReadOnlyConfig } from '../adapters-contract';\nimport { toRenderableData } from '../adapters-contract';\nimport type {\n API,\n Blok,\n BlockMutationEvent,\n BlockRenderedPayload,\n BlocksRenderedPayload,\n BlokConfig,\n EditorWidth,\n LiveHandlers,\n LooseOutputData,\n OutputBlockData,\n OutputData,\n ResolvedTheme,\n ThemeMode,\n} from '@bloklabs/core';\nimport type { BlokAngularConfig } from './types';\n\n/**\n * Warning text for a controlled `data` change the adapter refuses to render\n * under collaboration. Kept verbatim in all three adapters (they share no code).\n * @param doc - the collaboration document id, for the reset endpoint in the text\n * @returns the message to warn with, once per adapter instance\n */\nconst collaborationDataIgnoredMessage = (doc?: string): string =>\n '[Blok] `data` is ignored while collaboration is on: the document lives on the sync service ' +\n 'and is shared with everyone editing it, so replacing it from this editor would overwrite their work. ' +\n `To replace the whole document, call POST /sync/${doc ?? '{doc}'}/reset on your server — ` +\n 'it reloads the document from your own document endpoint and every open editor picks it up. ' +\n 'To change part of it, use the blocks API (insert/update/delete).';\n\n/**\n * The blessed all-in-one Angular component for embedding Blok (mirrors React's\n * `BlokEditor`). Delegates instance lifecycle to an internal `BlokContentDirective`\n * and layers the typed reactive input/output API on top.\n *\n * Reactive inputs (`readOnly`, `hideToolbar`, `toolbarPosition`,\n * `inlineToolbar`, `theme`, `width`, `placeholder`, `autofocus`, `styleTokens`,\n * `i18n`, `data`) are synced in place after mount via effects — `hideToolbar`\n * through `editor.toolbar.setHidden()`, `toolbarPosition` through\n * `editor.toolbar.setPosition()`, `inlineToolbar` through\n * `editor.tools.setInlineToolbar()` (content-compared),\n * `styleTokens` through `editor.tokens.set()` (replace semantics),\n * `i18n` through `editor.i18n.update()` (deep-equal–deduped; seeded at\n * construction so the locale resolves during boot) and `data`\n * through `editor.render()` (content-deduped via `equalsOutputData`); everything\n * else seeds construction.\n *\n * Implementation note: classic `@Input()`/`@ViewChild()` decorators are used\n * (not signal `input()`/`viewChild()`) for JIT compatibility — see\n * `BlokContentDirective`. Each reactive input is backed by an internal `signal`\n * so effect-based syncing still works; the public template API is unchanged.\n */\n@Component({\n selector: 'blok-editor',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n exportAs: 'blok',\n imports: [BlokContentDirective],\n template: `<div blokContent [config]=\"buildConfig()\" [recreateKey]=\"recreateKey\"></div>`,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => BlokEditorComponent),\n multi: true,\n },\n ],\n})\nexport class BlokEditorComponent implements AfterViewInit, DoCheck, ControlValueAccessor {\n private readonly ngZone = inject(NgZone);\n /** App-wide defaults from `provideBlok()`; merged UNDER per-instance inputs. */\n private readonly defaults = inject(BLOK_DEFAULT_CONFIG, { optional: true }) ?? {};\n\n @ViewChild(BlokContentDirective) private contentQuery?: BlokContentDirective;\n /** Signal bridge for the @ViewChild directive so effects react to its arrival. */\n private readonly content = signal<BlokContentDirective | null>(null);\n\n /**\n * Output half of two-way `[(data)]`. Emits the editor's serialized content on\n * every change. Wiring the core `onSave` callback is gated on this being\n * observed, since its mere presence makes the core serialize on every batch.\n */\n /** Emits the live Blok instance once ready, after `instance()` is populated. */\n @Output() readonly ready = new EventEmitter<Blok>();\n\n @Output() readonly dataChange = new EventEmitter<OutputData>();\n\n /** Fires with the full serialized content on every change (notification half). */\n @Output() readonly save = new EventEmitter<OutputData>();\n\n /** Raw block mutation channel (core `onChange`). */\n @Output() readonly change = new EventEmitter<{\n api: API;\n event: BlockMutationEvent | BlockMutationEvent[];\n }>();\n\n /** Fires after the editor finishes (re-)rendering (core `onAfterRender`). */\n @Output() readonly afterRender = new EventEmitter<API>();\n\n /** Fires with the resolved theme whenever it changes (core `onThemeChange`). */\n @Output() readonly themeChange = new EventEmitter<ResolvedTheme>();\n\n /** Fires after a batch render completes (core `blocks:rendered` event). */\n @Output() readonly blocksRendered = new EventEmitter<BlocksRenderedPayload>();\n\n /** Fires for each block rendered into the DOM (core `block:rendered` event). */\n @Output() readonly blockRendered = new EventEmitter<BlockRenderedPayload>();\n\n /**\n * Transform hook applied to blocks before render (core `onBeforeRender`). Must\n * return the (possibly modified) block list. An input, not an output, because\n * it returns a value.\n */\n @Input() onBeforeRender?: (blocks: OutputBlockData[]) => OutputBlockData[];\n\n /**\n * Transform hook applied to pasted HTML (core `onBeforePaste`). Returns the\n * (possibly modified) html, or null to drop the paste.\n */\n @Input() onBeforePaste?: (html: string) => string | null;\n\n /**\n * Error channel (core `onError`). Fires with the raised error whenever an\n * editor operation — currently serialization — fails instead of only logging.\n */\n @Input() onError?: BlokConfig['onError'];\n\n // ---- Reactive inputs (signal-backed setters; synced in place, never recreate) ----\n // Default undefined (not false) so an unset input falls back to a provideBlok\n // default; the readOnly effect / buildConfig coerce undefined to false.\n // Accepts the object form (`{ hideControls }`) too — it flows through\n // buildConfig unchanged and the effect expands it to\n // `readOnly.set(enabled, { hideControls })`.\n private readonly readOnly$ = signal<BlokConfig['readOnly'] | undefined>(undefined);\n @Input() set readOnly(value: BlokConfig['readOnly'] | undefined) {\n this.readOnly$.set(value);\n }\n\n private readonly hideToolbar$ = signal<boolean | undefined>(undefined);\n @Input() set hideToolbar(value: boolean | undefined) {\n this.hideToolbar$.set(value);\n }\n\n private readonly toolbarPosition$ = signal<BlokConfig['toolbarPosition'] | undefined>(undefined);\n @Input() set toolbarPosition(value: BlokConfig['toolbarPosition'] | undefined) {\n this.toolbarPosition$.set(value);\n }\n\n private readonly inlineToolbar$ = signal<boolean | string[] | undefined>(undefined);\n @Input() set inlineToolbar(value: boolean | string[] | undefined) {\n this.inlineToolbar$.set(value);\n }\n\n private readonly theme$ = signal<ThemeMode | undefined>(undefined);\n @Input() set theme(value: ThemeMode | undefined) {\n this.theme$.set(value);\n }\n\n private readonly width$ = signal<EditorWidth | undefined>(undefined);\n @Input() set width(value: EditorWidth | undefined) {\n this.width$.set(value);\n }\n\n private readonly placeholder$ = signal<string | false | undefined>(undefined);\n @Input() set placeholder(value: string | false | undefined) {\n this.placeholder$.set(value);\n }\n\n /**\n * Theme tokens. Construction-only config forced hosts with a live light/dark\n * toggle to recreate the editor or hand-write the global stylesheet Blok\n * already injects; this drives the runtime `tokens` API instead.\n */\n private readonly styleTokens$ = signal<Record<string, string> | undefined>(undefined);\n @Input() set styleTokens(value: Record<string, string> | undefined) {\n this.styleTokens$.set(value);\n }\n\n /**\n * Locale, host message overrides and text direction. `config.i18n` was\n * consumed once at boot, so a host driving a language switcher had to\n * recreate the editor (losing caret, focus and undo stack) to relabel the\n * UI; this drives the runtime `i18n.update` API instead. `defaultLocale` is\n * not forwarded — it only affects the INITIAL locale resolution.\n */\n private readonly i18n$ = signal<BlokConfig['i18n'] | undefined>(undefined);\n @Input() set i18n(value: BlokConfig['i18n'] | undefined) {\n this.i18n$.set(value);\n }\n\n private readonly autofocus$ = signal<boolean | undefined>(false);\n @Input() set autofocus(value: boolean | undefined) {\n this.autofocus$.set(value);\n }\n\n // ---- Reactive content (seeds construction, then re-renders on change) ----\n private readonly data$ = signal<OutputData | LooseOutputData | null | undefined>(undefined);\n @Input() set data(value: OutputData | LooseOutputData | null | undefined) {\n this.data$.set(value);\n }\n\n // ---- Construction-only seed inputs (read once at construction) ----\n @Input() tools?: BlokConfig['tools'];\n /** Host-supplied per-type block migrations applied at load (merged across layers). */\n @Input() migrations?: BlokConfig['migrations'];\n\n /**\n * Escape hatch: a full config object for keys without a dedicated input\n * (sanitizer, minHeight, …). Layered between provideBlok\n * defaults and the discrete inputs.\n */\n @Input() config?: Partial<BlokAngularConfig>;\n\n /** Changing this input's identity destroys and recreates the editor (≙ React `deps`). */\n @Input() recreateKey: unknown;\n\n /**\n * Content the editor currently reflects. Set when seeded, when the data effect\n * renders, when the editor emits its own output (`coreOnSave`) and when the\n * imperative `render()` facade lands. A controlled `data` echo that\n * content-equals this baseline is a no-op, so it won't clobber the caret.\n * Renders are serialized via `renderChain`. `undefined` means \"nothing recorded\n * yet\" — never an empty document.\n */\n private lastRenderedData?: OutputData | LooseOutputData | null;\n\n /** Last token set pushed through `tokens.set`, for deep-equal deduping. */\n private appliedTokens?: Record<string, string>;\n /** Last i18n config pushed through `i18n.update`, for deep-equal deduping. */\n private appliedI18n?: BlokConfig['i18n'];\n /** Editor instance the i18n baseline above belongs to. */\n private i18nAppliedFor: Blok | null = null;\n /** Last value pushed through `tools.setInlineToolbar`, for content-compare deduping. */\n private appliedInlineToolbar?: boolean | string[];\n private seededEditor: Blok | null = null;\n private renderChain: Promise<void> = Promise.resolve();\n /** One collaboration warning per component instance (see the data effect). */\n private collaborationWarned = false;\n /**\n * The `collaboration` the live editor was CONSTRUCTED with. The key is\n * mount-fixed, so dropping it from `[config]` (`collaboration: on ? {...} :\n * undefined`) cannot turn a live session into a single-player editor —\n * reading the current input instead would let that change fall through into\n * render(), which refuses under collaboration and rejects with nothing\n * surfaced anywhere.\n */\n private constructedCollaboration: BlokAngularConfig['collaboration'];\n /** Editor the capture above belongs to (recaptured on recreate). */\n private collaborationCapturedFor: Blok | null = null;\n\n /** Registered by `ControlValueAccessor.registerOnChange` (Angular forms). */\n private cvaOnChange?: (data: OutputData) => void;\n private cvaOnTouched?: () => void;\n\n /**\n * Core `onSave` wrapper. Records the editor's own serialized output as the\n * rendered baseline BEFORE notifying Angular, so a controlled consumer echoing\n * it straight back into `data` deep-equals the baseline and is deduped to a\n * no-op (no redundant render, no caret reset). Re-enters the Angular zone since\n * the editor runs outside it.\n *\n * Falls back to an escape-hatch `[config]` callback when nothing Angular-side\n * consumes the save — the baseline is recorded either way, so the controlled\n * `data` dedupe works on both paths.\n */\n private readonly coreOnSave = (data: OutputData, api: API): void => {\n this.lastRenderedData = data;\n\n if (this.hasSaveConsumer()) {\n this.ngZone.run(() => {\n this.dataChange.emit(data);\n this.save.emit(data);\n this.cvaOnChange?.(data);\n this.cvaOnTouched?.();\n });\n\n return;\n }\n\n this.escapeHatchConfig().onSave?.(data, api);\n };\n\n /**\n * Stable wrappers for the remaining live callbacks. Each resolves its target\n * at call time (an observed output, else the `[config]` escape hatch), so a\n * pushed handler never goes stale and only PRESENCE has to be synced.\n */\n private readonly coreOnChange = (\n api: API,\n event: BlockMutationEvent | BlockMutationEvent[]\n ): void => {\n if (this.change.observed) {\n this.ngZone.run(() => this.change.emit({ api, event }));\n\n return;\n }\n\n this.escapeHatchConfig().onChange?.(api, event);\n };\n\n private readonly coreOnAfterRender = (api: API): void => {\n if (this.afterRender.observed) {\n this.ngZone.run(() => this.afterRender.emit(api));\n\n return;\n }\n\n this.escapeHatchConfig().onAfterRender?.(api);\n };\n\n /*\n * Transforms run synchronously inside core's render pipeline and must return a\n * value — never wrap them in ngZone.run.\n */\n private readonly coreOnBeforeRender = (blocks: OutputBlockData[]): OutputBlockData[] => {\n const transform = this.onBeforeRender ?? this.escapeHatchConfig().onBeforeRender;\n\n return transform?.(blocks) ?? blocks;\n };\n\n private readonly coreOnEnter = (event: KeyboardEvent, api: API): boolean | void =>\n this.escapeHatchConfig().onEnter?.(event, api);\n\n private readonly coreOnSubmit = (data: OutputData, api: API): void => {\n this.escapeHatchConfig().onSubmit?.(data, api);\n };\n\n /** provideBlok defaults merged under the `[config]` escape hatch. */\n private escapeHatchConfig(): Partial<BlokAngularConfig> {\n return { ...this.defaults, ...this.config };\n }\n\n /** True when an output, a two-way binding or Angular forms consumes `onSave`. */\n private hasSaveConsumer(): boolean {\n return this.dataChange.observed || this.save.observed || this.cvaOnChange !== undefined;\n }\n\n /**\n * The live callbacks this component currently wires into core, keyed by\n * handler name — `undefined` for the ones nothing consumes.\n *\n * PRESENCE is the semantics in core (an `onSubmit` turns Enter into\n * serialize-and-submit, an `onSave` arms the change-observation pipeline), so\n * an unconsumed callback must stay absent. One source of truth for both the\n * construction config and the runtime sync in `ngDoCheck`, so the two cannot\n * drift.\n * @returns the wrappers to install, `undefined` where nothing is wired\n */\n private liveHandlers(): LiveHandlers {\n const cfg = this.escapeHatchConfig();\n\n return {\n onChange: this.change.observed || cfg.onChange !== undefined ? this.coreOnChange : undefined,\n onSave: this.hasSaveConsumer() || cfg.onSave !== undefined ? this.coreOnSave : undefined,\n onEnter: cfg.onEnter !== undefined ? this.coreOnEnter : undefined,\n onSubmit: cfg.onSubmit !== undefined ? this.coreOnSubmit : undefined,\n onBeforeRender:\n this.onBeforeRender !== undefined || cfg.onBeforeRender !== undefined\n ? this.coreOnBeforeRender\n : undefined,\n onAfterRender:\n this.afterRender.observed || cfg.onAfterRender !== undefined\n ? this.coreOnAfterRender\n : undefined,\n };\n }\n\n /** Handler presence installed on the live editor (the sync dedupe baseline). */\n private appliedHandlers: LiveHandlers = {};\n\n /** Live Blok instance, or null until `isReady` resolves / after destroy. */\n readonly instance = computed<Blok | null>(() => this.content()?.instance() ?? null);\n\n /** Guards `ready` to one emission per editor instance. */\n private lastReadyInstance: Blok | null = null;\n\n /**\n * Construction config handed to the directive. Seeds the editor's initial\n * values; the directive only reads it once (at construction), so post-mount\n * changes to construction-only inputs are no-ops by design.\n */\n buildConfig(): Partial<BlokAngularConfig> {\n // Precedence: provideBlok defaults < [config] escape hatch < discrete inputs.\n const cfg: Partial<BlokAngularConfig> = { ...this.defaults, ...this.config };\n\n // The object form ({ hideControls }) is preserved as-is; the readOnly\n // effect expands it into `readOnly.set(enabled, { hideControls })`.\n cfg.readOnly = this.readOnly$() ?? this.config?.readOnly ?? this.defaults.readOnly ?? false;\n\n const hideToolbar = this.hideToolbar$();\n\n if (hideToolbar !== undefined) {\n cfg.hideToolbar = hideToolbar;\n }\n\n const toolbarPosition = this.toolbarPosition$();\n\n if (toolbarPosition !== undefined) {\n cfg.toolbarPosition = toolbarPosition;\n }\n\n const inlineToolbar = this.inlineToolbar$();\n\n if (inlineToolbar !== undefined) {\n cfg.inlineToolbar = inlineToolbar;\n }\n\n // tools registries are MERGED (not replaced) across all three layers so a\n // shared registry composes with per-instance additions.\n if (\n this.tools !== undefined ||\n this.config?.tools !== undefined ||\n this.defaults.tools !== undefined\n ) {\n cfg.tools = { ...this.defaults.tools, ...this.config?.tools, ...this.tools };\n }\n\n // migration registries merge like tools: shared defaults compose with\n // per-instance rules.\n if (\n this.migrations !== undefined ||\n this.config?.migrations !== undefined ||\n this.defaults.migrations !== undefined\n ) {\n cfg.migrations = { ...this.defaults.migrations, ...this.config?.migrations, ...this.migrations };\n }\n\n const data = this.data$();\n\n if (data !== undefined) {\n cfg.data = data;\n }\n\n const theme = this.theme$();\n\n if (theme !== undefined) {\n cfg.theme = theme;\n }\n\n const width = this.width$();\n\n if (width !== undefined) {\n cfg.width = width;\n }\n\n const placeholder = this.placeholder$();\n\n if (placeholder !== undefined) {\n cfg.placeholder = placeholder;\n }\n\n // Seeded at construction (not applied by the i18n effect) so the locale is\n // resolved during boot instead of flashing the default language first.\n const i18n = this.i18n$();\n\n if (i18n !== undefined) {\n cfg.i18n = i18n;\n }\n\n // Opt-in: only attach each live callback when the consumer actually consumes\n // it (an observed output, a registered forms hook, a provided transform or an\n // escape-hatch config callback). Their mere presence makes the core serialize\n // / run hooks on every change. The same map drives the runtime sync in\n // `ngDoCheck`, so construction and post-mount can never disagree.\n const handlers = this.liveHandlers();\n\n cfg.onChange = handlers.onChange;\n cfg.onSave = handlers.onSave;\n cfg.onEnter = handlers.onEnter;\n cfg.onSubmit = handlers.onSubmit;\n cfg.onBeforeRender = handlers.onBeforeRender;\n cfg.onAfterRender = handlers.onAfterRender;\n\n this.appliedHandlers = handlers;\n\n if (this.themeChange.observed) {\n cfg.onThemeChange = (resolved: ResolvedTheme): void =>\n this.ngZone.run(() => this.themeChange.emit(resolved));\n }\n\n // Transforms run synchronously inside core's paste pipeline and must return a\n // value — never wrap them in ngZone.run.\n const beforePaste = this.onBeforePaste;\n\n if (beforePaste !== undefined) {\n cfg.onBeforePaste = (html: string): string | null => beforePaste(html);\n }\n\n const onError = this.onError;\n\n if (onError !== undefined) {\n cfg.onError = onError;\n }\n\n return cfg;\n }\n\n ngAfterViewInit(): void {\n this.content.set(this.contentQuery ?? null);\n }\n\n /**\n * Reactive callback presence.\n *\n * Callback wiring was decided once, at construction, and in core the presence\n * of a handler IS the semantics: an `onSubmit` makes Enter serialize-and-submit\n * instead of splitting the block, an `onSave` arms the whole change-observation\n * pipeline. A `[config]` swap, an `*ngIf`-gated `(save)` output or a\n * `registerOnChange` from Angular forms arriving after mount therefore needed a\n * `recreateKey` bump — destroying the editor and losing caret and undo history.\n *\n * Diff the wired handlers against what is installed and push genuine flips\n * through the runtime `handlers.set` API, writing `undefined` for a handler\n * that lost its consumer so the change stays reversible. `ngDoCheck` (not an\n * `effect`) because `EventEmitter.observed` and the plain `@Input` transforms\n * are not signals; the comparison is six identity checks against stable\n * wrappers, so an unchanged cycle pushes nothing.\n */\n ngDoCheck(): void {\n const editor = this.instance();\n\n if (editor === null) {\n return;\n }\n\n const desired = this.liveHandlers();\n const applied = this.appliedHandlers;\n const diff: LiveHandlers = {};\n const changed: { value: boolean } = { value: false };\n\n const sync = <K extends keyof LiveHandlers>(key: K, write: (value: LiveHandlers[K]) => void): void => {\n if (desired[key] === applied[key]) {\n return;\n }\n\n applied[key] = desired[key];\n changed.value = true;\n write(desired[key]);\n };\n\n sync('onChange', (value) => {\n diff.onChange = value;\n });\n sync('onSave', (value) => {\n diff.onSave = value;\n });\n sync('onEnter', (value) => {\n diff.onEnter = value;\n });\n sync('onSubmit', (value) => {\n diff.onSubmit = value;\n });\n sync('onBeforeRender', (value) => {\n diff.onBeforeRender = value;\n });\n sync('onAfterRender', (value) => {\n diff.onAfterRender = value;\n });\n\n if (changed.value) {\n editor.handlers.set(diff);\n }\n }\n\n // ---- Curated imperative facade (delegates to the live instance; no-ops until ready) ----\n\n /** Serialize the current content. Resolves undefined until the editor is ready. */\n save$(): Promise<OutputData> | undefined {\n return this.instance()?.save();\n }\n\n /** Move the caret into the editor. */\n focus(atEnd?: boolean): void {\n this.instance()?.focus(atEnd);\n }\n\n /**\n * Replace the editor content. Resolves undefined until the editor is ready.\n *\n * Safe to mix with a controlled `[data]` input: the rendered document becomes\n * the content baseline once the call lands, so a later `[data]` change back to\n * the previous document still re-renders instead of being deduped against a\n * baseline the editor no longer reflects. Recorded only on the resolved path —\n * a failed render leaves the editor on its previous content.\n * @param data - the document to render\n */\n render(data: OutputData | LooseOutputData): Promise<void> | undefined {\n const editor = this.instance();\n\n if (editor === null) {\n return undefined;\n }\n\n return editor.render(data).then(() => {\n this.lastRenderedData = data;\n });\n }\n\n constructor() {\n // Registered FIRST so the capture lands before the data effect below can\n // read it. `collaboration` reaches the directive through `buildConfig()`,\n // which is read once per build; this records what that build received.\n effect(() => {\n const editor = this.instance();\n\n if (editor !== null && editor !== this.collaborationCapturedFor) {\n this.collaborationCapturedFor = editor;\n this.constructedCollaboration = this.escapeHatchConfig().collaboration;\n }\n });\n\n // Each effect reads `instance()` so it re-applies once the editor appears\n // (the Angular analog of React's `editor` effect-dependency).\n effect(() => {\n const editor = this.instance();\n const readOnly = this.readOnly$() ?? this.config?.readOnly;\n\n if (editor) {\n const { enabled, hideControls } = normalizeReadOnlyConfig(readOnly);\n\n // Only the object form carries options; the boolean form keeps the\n // one-argument call so it never clobbers a config-seeded hideControls.\n if (typeof readOnly === 'object' && readOnly !== null) {\n void editor.readOnly.set(enabled, { hideControls });\n } else {\n void editor.readOnly.set(enabled);\n }\n }\n });\n\n effect(() => {\n const editor = this.instance();\n const hideToolbar = this.hideToolbar$();\n\n if (editor && hideToolbar !== undefined) {\n editor.toolbar.setHidden(hideToolbar);\n }\n });\n\n effect(() => {\n const editor = this.instance();\n const toolbarPosition = this.toolbarPosition$();\n\n if (editor && toolbarPosition !== undefined) {\n editor.toolbar.setPosition(toolbarPosition);\n }\n });\n\n // Content-compared (not identity): a new array with the same tool names is\n // a no-op, so template-inline array literals don't thrash the assignment.\n effect(() => {\n const editor = this.instance();\n const inlineToolbar = this.inlineToolbar$();\n\n if (\n !editor ||\n inlineToolbar === undefined ||\n deepEqual(inlineToolbar, this.appliedInlineToolbar)\n ) {\n return;\n }\n\n this.appliedInlineToolbar = Array.isArray(inlineToolbar) ? [...inlineToolbar] : inlineToolbar;\n editor.tools.setInlineToolbar(inlineToolbar);\n });\n\n effect(() => {\n const editor = this.instance();\n const theme = this.theme$();\n\n if (editor && theme !== undefined) {\n editor.theme.set(theme);\n }\n });\n\n effect(() => {\n const editor = this.instance();\n const width = this.width$();\n\n if (editor && width !== undefined) {\n editor.width.set(width);\n }\n });\n\n effect(() => {\n const editor = this.instance();\n const placeholder = this.placeholder$();\n\n if (editor && placeholder !== undefined) {\n editor.placeholder.set(placeholder);\n }\n });\n\n effect(() => {\n const editor = this.instance();\n const tokens = this.styleTokens$() ?? this.config?.style?.tokens;\n\n if (!editor || tokens === undefined || deepEqual(tokens, this.appliedTokens)) {\n return;\n }\n\n this.appliedTokens = { ...tokens };\n editor.tokens.set(tokens);\n });\n\n effect(() => {\n const editor = this.instance();\n const i18n = this.i18n$() ?? this.config?.i18n;\n\n if (!editor) {\n return;\n }\n\n /*\n * A freshly constructed editor already resolved this config during its\n * own boot (buildConfig seeds it), so record the baseline and push\n * nothing — re-applying it here would reload the locale after mount and\n * flash the default language.\n */\n if (this.i18nAppliedFor !== editor) {\n this.i18nAppliedFor = editor;\n this.appliedI18n = i18n === undefined ? undefined : { ...i18n };\n\n return;\n }\n\n if (i18n === undefined || deepEqual(i18n, this.appliedI18n)) {\n return;\n }\n\n this.appliedI18n = { ...i18n };\n\n const { locale, messages, direction } = i18n;\n\n void editor.i18n.update({\n ...(locale === undefined ? {} : { locale }),\n ...(messages === undefined ? {} : { messages }),\n ...(direction === undefined ? {} : { direction }),\n });\n });\n\n effect(() => {\n const editor = this.instance();\n\n if (editor && this.autofocus$()) {\n editor.focus();\n }\n });\n\n // Reactive content. `data` seeds the editor at construction; afterwards a new\n // *content* value re-renders via the public render() API (deep-equal-deduped\n // and serialized, so an unchanged reference — including the editor's own\n // echoed output — is a no-op and never clobbers the caret).\n effect(() => {\n const editor = this.instance();\n const data = this.data$();\n\n if (!editor || data === undefined) {\n return;\n }\n\n // A freshly created editor was already seeded with `data` at construction;\n // record it without re-rendering.\n if (this.seededEditor !== editor) {\n this.seededEditor = editor;\n this.lastRenderedData = data;\n\n return;\n }\n\n // Structural comparison (`equalsOutputData`, not a raw deep-equal): a host\n // that persists the editor's own document and hands back a stripped copy —\n // fresh `time`, dropped ids, no `lastEditedAt` stamp — is still echoing\n // content the editor already shows, and re-rendering it would reset the\n // caret for zero visual change. `undefined` means \"nothing recorded yet\",\n // which is NOT an empty document, so it must never match.\n const baseline = this.lastRenderedData;\n\n if (baseline !== undefined && equalsOutputData(data, baseline)) {\n return;\n }\n\n // Under collaboration the document belongs to the sync service, and\n // render() refuses a wholesale replace — so don't attempt one. The input's\n // premise (\"this value IS the document\") does not hold here. Decided\n // against the MOUNTED config, never the current input: `collaboration` is\n // mount-fixed, so a host that drops the key is still driving a\n // collaboration session and deserves the warning rather than a silently\n // rejected render.\n const collaboration = this.constructedCollaboration;\n\n if (collaboration !== undefined) {\n if (!this.collaborationWarned) {\n this.collaborationWarned = true;\n console.warn(collaborationDataIgnoredMessage(collaboration.doc));\n }\n\n return;\n }\n\n this.lastRenderedData = data;\n // `data` may be null (a controlled \"clear to empty\"); render() throws on\n // null, so normalize null → { blocks: [] } at the boundary.\n this.renderChain = this.renderChain.catch(() => undefined).then(() => editor.render(toRenderableData(data)));\n });\n\n // Emit `ready` once per editor, after `instance()` is populated so a consumer\n // reading the component/ref instance inside the handler sees it.\n effect(() => {\n const editor = this.instance();\n\n if (editor && editor !== this.lastReadyInstance) {\n this.lastReadyInstance = editor;\n this.ready.emit(editor);\n }\n });\n\n // Subscribe to the editor's rendered-lifecycle events once it exists (gated on\n // the outputs being observed). `onCleanup` unsubscribes when the instance is\n // replaced or the component is destroyed.\n effect((onCleanup) => {\n const editor = this.instance();\n\n if (!editor) {\n return;\n }\n\n const handlers: Array<[string, (payload?: unknown) => void]> = [];\n\n if (this.blocksRendered.observed) {\n const handler = (payload?: unknown): void =>\n this.ngZone.run(() => this.blocksRendered.emit(payload as BlocksRenderedPayload));\n\n editor.on('blocks:rendered', handler);\n handlers.push(['blocks:rendered', handler]);\n }\n\n if (this.blockRendered.observed) {\n const handler = (payload?: unknown): void =>\n this.ngZone.run(() => this.blockRendered.emit(payload as BlockRenderedPayload));\n\n editor.on('block:rendered', handler);\n handlers.push(['block:rendered', handler]);\n }\n\n onCleanup(() => {\n for (const [name, handler] of handlers) {\n editor.off(name, handler);\n }\n });\n });\n }\n\n // ---- ControlValueAccessor (optional forms integration) ----\n\n /** Seeds/renders an externally-set form value through the same dedup machinery. */\n writeValue(value: OutputData | LooseOutputData | null): void {\n this.data$.set(value ?? undefined);\n }\n\n registerOnChange(fn: (data: OutputData) => void): void {\n this.cvaOnChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.cvaOnTouched = fn;\n }\n\n /** Form disabled state maps to the editor's read-only mode (via the readOnly effect). */\n setDisabledState(isDisabled: boolean): void {\n this.readOnly$.set(isDisabled);\n }\n}\n","import type { API, BlockAPI, BlockOrigin, BlockToolConstructable, BlockToolConstructorOptions, BlockToolData, ToolboxConfig } from '@bloklabs/core';\n// packages/angular/src/createAngularBlock.ts\nimport { signal, type Type, type WritableSignal } from '@angular/core';\n\nimport {\n applyChildDecoration,\n BlockChildrenMounted,\n createChildDecorationLedger,\n DATA_ATTR,\n} from '../adapters-contract';\nimport { deepEqual } from '../adapters-contract';\nimport { fillDefaults, type PropSchema } from '../adapters-contract';\nimport { mountChildBlocks } from '../adapters-contract';\n\nimport type { AngularBlockRenderContext, ChildAttributesFn } from './block-context';\nimport { BLOK_PORTAL_REGISTRY_CONFIG_KEY, type BlockPortalRegistry } from './block-portal-registry';\n\n/**\n * Every STATIC member of core's block-tool contract an Angular block may declare\n * for itself — `ownsChildren`, `keepsChildrenOnEnter`, `conversionConfig`,\n * `pasteConfig`, `sanitize`, `shortcut`, `upgradeData`, and whatever core adds\n * next. Derived from\n * `BlockToolConstructable` rather than enumerated, so a new core static needs no\n * adapter change to become reachable.\n *\n * `toolbox` and `isReadOnlySupported` are excluded because the factory owns\n * them: `toolbox` is authored as {@link CreateAngularBlockSpec.toolbox}, and\n * in-place read-only support is unconditional.\n */\nexport type BlockToolStatics = Omit<BlockToolConstructable, 'toolbox' | 'isReadOnlySupported'>;\n\n/** Statics the generated class owns; an authored `statics` bag can never take them over. */\nconst RESERVED_STATICS: readonly string[] = ['toolbox', 'isReadOnlySupported', '__isBlokAngularBlock'];\n\n/**\n * Origins that mean \"the author just made this block\" — the only ones that fire\n * {@link CreateAngularBlockSpec.onCreated}. Written as an allow-list so a future\n * core origin fails CLOSED (no creation signal) instead of silently opting in.\n *\n * `undefined` is included because core always supplies an origin: an absent one\n * means a host hand-built the constructor options, which is an explicit\n * creation — the same reading core's own container tools apply.\n *\n * Note what is NOT the axis here: `origin === 'user'`. A container gated on that\n * alone would refuse to seed for `api.blocks.insert('steps')` and for a\n * turn-into, leaving an empty, unusable container.\n */\nconst CREATION_ORIGINS: ReadonlySet<BlockOrigin | undefined> = new Set<BlockOrigin | undefined>([\n undefined,\n 'user',\n 'api',\n 'convert',\n]);\n\n/**\n * Announce that a container's child holders have settled in its slot — the\n * signal a host waits on before putting the caret into a freshly inserted\n * child.\n *\n * Optional-chained: the editor always supplies `events`, but a host unit test\n * may hand a block a partial `api`, and an observability signal must never be\n * able to break a render.\n * @param api - the editor-level API\n * @param blockId - the container block's id\n * @param children - the container's model children, in model order\n */\nconst emitChildrenMounted = (api: API, blockId: string, children: BlockAPI[]): void => {\n api?.events?.emit(BlockChildrenMounted, {\n blockId,\n childIds: children.map(child => child.id),\n });\n};\n\n/**\n * Second argument of {@link CreateAngularBlockSpec.onMounted} and\n * {@link CreateAngularBlockSpec.onCreated} — everything the block cannot read\n * off its own `BlockAPI`.\n */\nexport interface AngularBlockMountedContext {\n /**\n * Why this block instance was constructed: a CREATION origin (`user`, `api`,\n * `convert`) means the author just made it, so seeding default children is\n * correct; a RESTORE origin (`load`, `replay`, `paste`) means the document\n * already says what the children are. `probe` is an off-tree instance built\n * only to read a tool's default data — it must not touch the block tree at\n * all. Defaults to `'api'` when the constructor was handed no origin.\n */\n origin: BlockOrigin;\n /** The editor-level API (`api.blocks`, `api.caret`, `api.events`…). */\n api: API;\n}\n\n/** Spec for {@link createAngularBlock}. Authored as a standalone component. */\nexport interface CreateAngularBlockSpec<Data = BlockToolData> {\n /** Tool type name (registered key). */\n type: string;\n /** Optional toolbox entry. */\n toolbox?: ToolboxConfig;\n /** Declarative defaults that also define the exact `save()` key set. */\n propSchema: PropSchema;\n /**\n * The standalone Angular component to render for each block. It injects the\n * per-block context via `inject(BLOK_BLOCK_CONTEXT)`.\n */\n component: Type<unknown>;\n /**\n * Static members of core's tool contract, forwarded verbatim onto the\n * generated tool class — the single channel for everything core reads off the\n * CLASS rather than the instance (`ownsChildren`, `keepsChildrenOnEnter`,\n * `conversionConfig`, `pasteConfig`, `sanitize`, `shortcut`, `upgradeData`…).\n * Without it the only way to declare one was to subclass the generated class.\n *\n * `keepsChildrenOnEnter` is the per-tool Enter POLICY: declare it and Enter on\n * this container's empty LAST child creates the new line INSIDE the container\n * instead of escaping to the container's parent (Blok's default, which is\n * Notion's callout behaviour). Core cannot read that off the DOM — a callout\n * renders the same `data-blok-nested-blocks` slot as a column yet wants the\n * escape — so before it existed a layout container (a card, a `steps` block)\n * had to hijack the editor-global `config.onEnter` and re-derive containment.\n *\n * `toolbox` and `isReadOnlySupported` are owned by the factory and cannot be\n * overridden here (see {@link BlockToolStatics}).\n */\n statics?: BlockToolStatics;\n /**\n * The element the +/drag toolbar should vertically center on — core's\n * `getToolbarAnchorElement` hook, resolved against this block's host element\n * on every call (never cached, so it tracks re-renders).\n *\n * A container block whose own chrome is not editable needs it: with no anchor,\n * core centers the toolbar on the first `[contenteditable]` under the host,\n * which for a container is its FIRST CHILD BLOCK. Return `null`/`undefined`\n * (or omit the field) to keep core's default.\n * @param host - this block's mutation-free host element\n * @param block - this block's per-block API\n */\n getToolbarAnchorElement?: (host: HTMLElement, block: BlockAPI) => HTMLElement | null | undefined;\n /** Optional lifecycle callbacks mapped from Blok's block hooks. */\n onRendered?: (block: BlockAPI) => void;\n /**\n * Fired ONCE per block instance, once the component's DOM (and, for a\n * container, the child holders its `ctx.mountChildren` adopted) exists.\n * Angular mounts the block synchronously while core is still inside\n * `render()`, so this lands with `rendered()` — the first hook at which the\n * host is also in the document. The React and Vue adapters spell the same\n * contract; there it is genuinely LATER than `onRendered`, because their\n * portals commit a frame after core returns.\n *\n * It is also the create-vs-restore signal: `context.origin` says whether the\n * author just made this block (`user`/`api`/`convert`) or the document is\n * being re-materialised (`load`/`replay`/`paste`) — so a container can seed\n * its default children here exactly once, without the \"children are\n * transiently empty during a replay\" trap.\n * @example\n * ```ts\n * onMounted: (block, { origin, api }) => {\n * if (origin === 'user' && block.getChildren().length === 0) {\n * api.blocks.insertInsideParent(block.id);\n * }\n * }\n * ```\n */\n onMounted?: (block: BlockAPI, context: AngularBlockMountedContext) => void;\n /**\n * The SEEDING hook: `onMounted`, narrowed to a genuine creation. Fired ONCE\n * per block instance, once the component's DOM exists, and only when this\n * instance is the author making a new block (`origin` of `user`, `api` or\n * `convert`) — never for a `load`/`replay`/`paste` restore, and never for the\n * off-tree `probe` instance core builds to read a tool's default data.\n *\n * That predicate is why the hook exists rather than leaving every block to\n * read `context.origin` in `onMounted`: the intuitive `origin === 'user'` test\n * is wrong. It drops `api.blocks.insert('steps')` and turn-into, so a\n * container seeded that way comes up empty for every path except a keystroke.\n * Core refused to ship that axis into its own `column`/`column_list`; this\n * encodes the correct one once, here.\n *\n * The `context` is the same object {@link CreateAngularBlockSpec.onMounted}\n * receives, so a block that only seeds can read `origin` for finer decisions.\n * @example\n * ```ts\n * onCreated: (block, { api }) => {\n * if (block.getChildren().length === 0) {\n * api.blocks.insertInsideParent(block.id);\n * }\n * }\n * ```\n */\n onCreated?: (block: BlockAPI, context: AngularBlockMountedContext) => void;\n onMoved?: (block: BlockAPI) => void;\n onRemoved?: (block: BlockAPI) => void;\n}\n\n/**\n * Author a first-party Angular block. Returns a `BlockToolConstructable`\n * registered exactly like a vanilla tool (`tools: { type: { class:\n * createAngularBlock(...) } }`).\n *\n * The factory owns the host element (`data-blok-mutation-free`), a frozen\n * defaults-filled data mirror, and signals the component reads. It mounts the\n * component into the host via the editor's shared portal registry (the analog of\n * Vue's Teleport registry), bridging Blok's block lifecycle to Angular:\n * - `render()` creates the host and registers the portal entry (mounted sync).\n * - `setData()` dedups, swaps the reactive snapshot, flushes CD, resolves true.\n * - `save()` returns the complete frozen mirror (never the DOM, never partial).\n * - `commit()` merges a patch and fires `dispatchChange` exactly once.\n * - `setReadOnly()` flips a reactive flag and flushes CD (in-place, no remount).\n * - `removed()`/`destroy()` unregister the portal (deterministic unmount).\n */\nexport function createAngularBlock<Data = BlockToolData>(\n spec: CreateAngularBlockSpec<Data>\n): (new (options: BlockToolConstructorOptions) => {\n render(): HTMLElement;\n save(): BlockToolData;\n setData(newData: BlockToolData): Promise<boolean>;\n setReadOnly(state: boolean): void;\n getToolbarAnchorElement(): HTMLElement | undefined;\n rendered(): void;\n moved(): void;\n removed(): void;\n destroy(): void;\n}) & BlockToolStatics & {\n readonly __isBlokAngularBlock: true;\n readonly toolbox: ToolboxConfig | undefined;\n readonly isReadOnlySupported: boolean;\n} {\n const AngularBlockTool = class AngularBlockTool {\n /** Marker so the directive can detect Angular-block tools and inject the registry. */\n public static readonly __isBlokAngularBlock = true as const;\n\n public static get toolbox(): ToolboxConfig | undefined {\n return spec.toolbox;\n }\n\n /**\n * Angular blocks support read-only mode: `setReadOnly` flips a reactive flag\n * the component reads, so the block re-renders read-only IN PLACE. Without\n * this static, core's ReadOnly module throws when read-only is enabled and an\n * Angular block is present.\n */\n public static get isReadOnlySupported(): boolean {\n return true;\n }\n\n private readonly blockApi: BlockAPI;\n /** The editor-level API, handed to the component as `ctx.api`. */\n private readonly api: API;\n private readonly registry: BlockPortalRegistry | undefined;\n private readonly pointerDrag: () => boolean;\n private readonly dataSig: WritableSignal<Readonly<Data>>;\n private readonly readOnlySig: WritableSignal<boolean>;\n private readonly ctx: AngularBlockRenderContext<Data>;\n private mirror: Readonly<Data>;\n /** Dedup baseline: skip a redundant flush of identical data. */\n private lastRendered: Readonly<Data>;\n private hostEl: HTMLElement | null = null;\n /** Last host passed to ctx.mountChildren, re-mounted on each data change. */\n private childHost: HTMLElement | null = null;\n /** Element the component handed to ctx.setToolbarAnchor, if any. */\n private anchorEl: HTMLElement | null = null;\n /**\n * Last per-child decorators passed to ctx.mountChildren; BOTH re-applied on\n * every remount (the author calls mountChildren once, the factory re-runs the\n * mount on each data change).\n */\n private childAttributes: ChildAttributesFn | undefined;\n private childContentAttributes: ChildAttributesFn | undefined;\n /** What the last decoration pass wrote, so a dropped key is cleaned up. */\n private readonly childLedger = createChildDecorationLedger();\n /** Why core built this instance — gates `onCreated`, handed to `onMounted`. */\n private readonly origin: BlockOrigin;\n /** True once the post-mount hooks fired; a repeated rendered() must not re-fire them. */\n private mountSignalled = false;\n /** True while a pointer drag suppresses dispatchChange. */\n private pendingDispatch = false;\n\n public constructor(options: BlockToolConstructorOptions) {\n this.blockApi = options.block;\n\n const config = (options.config ?? {}) as Record<string, unknown>;\n\n this.registry = config[BLOK_PORTAL_REGISTRY_CONFIG_KEY] as BlockPortalRegistry | undefined;\n\n this.api = options.api;\n\n // Read the LIVE pointer-drag flag so a mid-drag commit can be deferred\n // (core silently drops a dispatchChange while a drag is active).\n const drag = options.api as unknown as { blocks?: { isPointerDragActive?: boolean } } | undefined;\n\n this.pointerDrag = (): boolean => drag?.blocks?.isPointerDragActive === true;\n\n this.mirror = fillDefaults<Data>(spec.propSchema, (options.data ?? {}) as Record<string, unknown>);\n this.lastRendered = this.mirror;\n this.dataSig = signal(this.mirror);\n this.readOnlySig = signal(options.readOnly);\n // Absent origin means a caller that predates the signal; 'api' is core's\n // own default, so it is never mistaken for a user gesture.\n this.origin = options.origin ?? 'api';\n\n this.ctx = {\n data: this.dataSig.asReadonly(),\n commit: this.commit,\n block: this.blockApi,\n api: this.api,\n readOnly: this.readOnlySig.asReadonly(),\n mountChildren: this.mountChildren,\n setToolbarAnchor: this.setToolbarAnchor,\n };\n }\n\n public render(): HTMLElement {\n const host = document.createElement('div');\n\n // Core's MutationObserver ignores this subtree, so Angular's DOM writes\n // never register as a user edit.\n host.setAttribute('data-blok-mutation-free', 'true');\n this.hostEl = host;\n\n this.registry?.register(this.blockApi.id, {\n hostEl: host,\n component: spec.component,\n context: this.ctx as AngularBlockRenderContext<unknown>,\n });\n\n return host;\n }\n\n public rendered(): void {\n spec.onRendered?.(this.blockApi);\n\n // register() mounted the component and ran its first change detection\n // synchronously inside render(), and core has now put the host in the\n // document — so this is the settled moment. Once per instance: core\n // re-runs rendered() for a re-materialised block, and a repeated creation\n // signal would seed a container's default children twice. With no\n // registry (vanilla core, no directive) nothing was ever mounted, so\n // there is no settle to report — matching React/Vue, where the signal\n // originates in the component itself.\n if (this.registry === undefined || this.mountSignalled) {\n return;\n }\n\n this.mountSignalled = true;\n\n const context = { origin: this.origin, api: this.api };\n\n spec.onMounted?.(this.blockApi, context);\n\n // Creation-only, and after onMounted: a seeding hook must see whatever\n // the mount hook already put in place.\n if (CREATION_ORIGINS.has(this.origin)) {\n spec.onCreated?.(this.blockApi, context);\n }\n }\n\n public save(): BlockToolData {\n return this.mirror as BlockToolData;\n }\n\n public async setData(newData: BlockToolData): Promise<boolean> {\n const next = fillDefaults<Data>(spec.propSchema, (newData ?? {}) as Record<string, unknown>);\n\n // Dedup: identical data → skip the flush, but still return true so core\n // keeps the block in place (no remount).\n if (deepEqual(next, this.lastRendered)) {\n return true;\n }\n\n this.mirror = next;\n this.lastRendered = next;\n this.dataSig.set(next);\n // Synchronous CD: core drives setData outside NgZone, so nothing else\n // schedules a render. Never throw (a throw would make core remount).\n this.registry?.flush(this.blockApi.id);\n this.remountChildren();\n\n // Resolve after a microtask for interface symmetry with the async core\n // setData contract; CD has already flushed synchronously above.\n await Promise.resolve();\n\n return true;\n }\n\n /**\n * In-place read-only toggle. Flips the reactive flag the component reads via\n * `ctx.readOnly`, then flushes CD so the block re-renders read-only WITHOUT a\n * remount (ephemeral state survives). A prototype method (not an arrow field)\n * so core's `supportsInPlaceReadOnly` — which probes the PROTOTYPE — selects\n * the in-place path.\n */\n public setReadOnly(state: boolean): void {\n this.readOnlySig.set(state);\n this.registry?.flush(this.blockApi.id);\n }\n\n /**\n * Core's toolbar-anchor hook. Always defined so the delegation is one\n * `typeof … === 'function'` probe away, and always resolved fresh against\n * the LIVE host — the anchor element is Angular-rendered, so it does not\n * exist yet when the tool is constructed and may be replaced on any change\n * detection pass. A spec without a resolver returns undefined, which is\n * exactly what core's default positioning already assumes.\n */\n public getToolbarAnchorElement(): HTMLElement | undefined {\n /**\n * An element the component handed over wins — it is the exact node, chosen\n * from inside the template. `isConnected` is the guard that matters: a\n * component that re-renders its anchor can leave a detached node here, and\n * positioning the toolbar against one silently parks it at 0,0.\n */\n const declared = this.anchorEl;\n\n if (declared !== null && declared.isConnected) {\n return declared;\n }\n\n const host = this.hostEl;\n\n if (host === null || spec.getToolbarAnchorElement === undefined) {\n return undefined;\n }\n\n return spec.getToolbarAnchorElement(host, this.blockApi) ?? undefined;\n }\n\n /**\n * `ctx.setToolbarAnchor`. A bound field so the context object handed through\n * DI keeps a stable identity.\n * @param element - the anchor element, or null to fall back to the spec hook\n */\n private readonly setToolbarAnchor = (element: HTMLElement | null): void => {\n this.anchorEl = element;\n };\n\n public moved(): void {\n // No remount: core relocates the host element; the mounted view rides along\n // as its DOM children.\n spec.onMoved?.(this.blockApi);\n }\n\n public removed(): void {\n // Ownership-scoped: core composes a REPLACEMENT block (which mounts under\n // the SAME id) before it tears this one down, so an unqualified unregister\n // here would destroy the live componentRef and blank the block.\n this.registry?.unregister(this.blockApi.id, this.hostEl ?? undefined);\n spec.onRemoved?.(this.blockApi);\n }\n\n public destroy(): void {\n // Idempotent with removed(); unregister is safe when already absent.\n this.registry?.unregister(this.blockApi.id, this.hostEl ?? undefined);\n }\n\n /**\n * Container blocks: remember the host (and any per-child decorator) and\n * (re)mount the real child holders.\n */\n private readonly mountChildren = (\n host: HTMLElement,\n childAttributes?: ChildAttributesFn,\n childContentAttributes?: ChildAttributesFn\n ): void => {\n this.childHost = host;\n this.childAttributes = childAttributes;\n this.childContentAttributes = childContentAttributes;\n host.setAttribute(DATA_ATTR.nestedBlocks, '');\n this.remountChildren();\n };\n\n private remountChildren(): void {\n if (this.childHost === null) {\n return;\n }\n\n const children = this.blockApi.getChildren();\n\n mountChildBlocks(this.childHost, children);\n applyChildDecoration(this.childLedger, children, {\n childAttributes: this.childAttributes,\n childContentAttributes: this.childContentAttributes,\n });\n emitChildrenMounted(this.api, this.blockApi.id, children);\n }\n\n /**\n * The only data write path. Merges the patch into the frozen mirror, swaps\n * the reactive snapshot, flushes CD, and fires dispatchChange EXACTLY once —\n * deferring it while a pointer drag is active (core would otherwise silently\n * drop it).\n */\n private readonly commit = (patch: Partial<Data>): void => {\n const next = fillDefaults<Data>(spec.propSchema, {\n ...(this.mirror as Record<string, unknown>),\n ...(patch as Record<string, unknown>),\n });\n\n // Idempotent: a patch that changes nothing is a full no-op — no signal\n // swap, no CD flush, no dispatchChange — so an effect echoing the current\n // value back through commit can never loop.\n if (deepEqual(next, this.mirror)) {\n return;\n }\n\n this.mirror = next;\n this.lastRendered = next;\n this.dataSig.set(next);\n this.registry?.flush(this.blockApi.id);\n this.remountChildren();\n this.flushDispatch();\n };\n\n /** Dispatch the change, or retry on the next frame if a drag is in progress. */\n private flushDispatch(): void {\n if (!this.pointerDrag()) {\n this.pendingDispatch = false;\n this.blockApi.dispatchChange();\n\n return;\n }\n\n if (this.pendingDispatch) {\n return;\n }\n\n this.pendingDispatch = true;\n\n const retry = (): void => {\n if (this.pointerDrag()) {\n requestAnimationFrame(retry);\n\n return;\n }\n\n this.pendingDispatch = false;\n this.blockApi.dispatchChange();\n };\n\n requestAnimationFrame(retry);\n }\n };\n\n // Forward the authored statics onto the generated class. `defineProperty`\n // (not assignment) because `toolbox`/`isReadOnlySupported` are accessors and a\n // plain write would throw in strict mode; the reserved list keeps a stray bag\n // from taking those — or the adapter's own marker — over.\n for (const [key, value] of Object.entries(spec.statics ?? {})) {\n if (RESERVED_STATICS.includes(key)) {\n continue;\n }\n\n Object.defineProperty(AngularBlockTool, key, {\n value,\n writable: true,\n enumerable: true,\n configurable: true,\n });\n }\n\n return AngularBlockTool;\n}\n","import type { Blok } from '@bloklabs/core';\n// packages/angular/src/useBlocks.ts\nimport { DestroyRef, effect, inject, signal, type Signal } from '@angular/core';\n\nimport { changeTouchesSubtree, createBlocksApiForEditor, EMPTY_API } from '../adapters-contract';\n\nimport type { UseBlocksApi } from './blocks-snapshot';\n\nconst BLOCK_CHANGED_EVENT = 'block changed';\n\n/** Options for {@link injectBlocks}. */\nexport interface InjectBlocksOptions {\n /**\n * Invalidate reads only for changes inside the subtree rooted at this block id\n * (the block itself or any descendant). Omit — or pass `null` — for the\n * document-wide default.\n *\n * This bounds REACTIVITY, not reads: the returned API still sees the whole\n * tree, so a scoped consumer can still `getById` anything. Reach for it in a\n * container block that renders only its own children — unscoped, such a block\n * invalidates on every keystroke anywhere in the document, and a page of N\n * containers turns one keystroke into N re-renders.\n *\n * Accepted as a plain value or a signal (like `editor`) and read at EMIT time,\n * so changing it takes effect immediately with no re-subscription.\n *\n * A change whose block cannot be placed in the tree (a removal that emits\n * after the block is gone) counts as in-scope: skipping it would leave a\n * container rendering a child that no longer exists.\n */\n within?: Signal<string | null> | string | null;\n}\n\n/**\n * Angular factory exposing an id/parentId-relative, reactive view of the block\n * tree. Reads refresh whenever the editor emits `block changed`; mutators route\n * through the editor-level `blocks` API (core's chokepoints), so undo/redo and\n * Yjs sync are inherited rather than re-implemented.\n *\n * The block-tree logic is framework-agnostic and lives in the shared\n * {@link createBlocksApiForEditor} core — the SAME implementation behind React's\n * and Vue's `useBlocks`, so all three adapters expose the identical 28-method\n * surface and cannot drift. This wrapper supplies only Angular's reactivity:\n *\n * - A private `version` signal is bumped on every `block changed`. The shared API\n * is built with an `onRead` seam (`() => { version() }`) that every read method\n * calls, so reading inside a `computed`/template tracks `version` and re-runs on\n * each structural mutation.\n * - The bound API is rebuilt (via `bindToEditor`, called eagerly on first call and\n * then tracked by an `effect` for subsequent identity changes) when the editor\n * IDENTITY changes; the returned facade is stable across that swap.\n *\n * Call it in an injection context (component constructor / field initializer),\n * passing the editor signal (e.g. `BlokEditorComponent.instance` /\n * `BlokContentDirective.instance`). Pre-ready (editor null) the bound API is the\n * shared {@link EMPTY_API}: every mutator a no-op, reads empty/null — except\n * `transact`/`transactWithoutCapture`, which still run their callback.\n *\n * Note: Angular 20's `effect()` is scheduled (not eager) — it does not fire\n * synchronously on first call. The initial binding therefore runs synchronously\n * in the `injectBlocks` body itself (mirroring Vue's `{ immediate: true }` watch),\n * and the effect re-binds only on subsequent editor identity changes. When the\n * effect fires for the first time with the same editor already bound, the guard\n * `ed === sub.editor` makes it a no-op, so no double-subscription occurs.\n *\n * @param editor - a signal of the Blok instance, or null pre-ready\n * @param options - reactivity options; see {@link InjectBlocksOptions.within} to\n * scope invalidation to one block's subtree\n */\nexport function injectBlocks(\n editor: Signal<Blok | null>,\n options: InjectBlocksOptions = {}\n): UseBlocksApi {\n /**\n * The scope, resolved per emission so a signal `within` takes effect with no\n * re-subscription. A signal is a zero-arg function, which is how it is told\n * apart from a plain id.\n */\n const resolveWithin = (): string | null =>\n (typeof options.within === 'function' ? options.within() : options.within) ?? null;\n\n // Bumped on every `block changed`; the shared API's read methods touch it (via\n // the onRead seam) so template/computed reads stay reactive.\n const version = signal(0);\n const touch = (): void => {\n version();\n };\n\n // The API bound to the CURRENT editor; EMPTY_API while null. A signal so the\n // facade's reads track the editor-identity swap.\n const bound = signal<UseBlocksApi>(EMPTY_API);\n\n // One subscription record (no `let` reassignment), re-bound on editor change.\n const sub: { editor: Blok | null; handler: ((payload?: unknown) => void) | null } = { editor: null, handler: null };\n\n const unsubscribe = (): void => {\n if (sub.editor !== null && sub.handler !== null) {\n sub.editor.off(BLOCK_CHANGED_EVENT, sub.handler);\n }\n sub.editor = null;\n sub.handler = null;\n };\n\n /**\n * Bind to `ed` if the identity has changed. Guards `ed === sub.editor` so a\n * deferred first effect-run with the same editor already bound is a no-op\n * (no double-subscription). Called synchronously on first call (immediate\n * binding) and then re-tracked by the effect below (future identity changes).\n */\n const bindToEditor = (ed: Blok | null): void => {\n if (ed === sub.editor) {\n return; // Same editor already bound; nothing to do.\n }\n\n unsubscribe();\n // A changed editor identity is itself a reason to re-read.\n version.update((v) => v + 1);\n\n if (ed === null) {\n bound.set(EMPTY_API);\n\n return;\n }\n\n const handler = (payload?: unknown): void => {\n const within = resolveWithin();\n\n if (within !== null && !changeTouchesSubtree(ed, payload, within)) {\n return;\n }\n\n version.update((v) => v + 1);\n };\n\n ed.on(BLOCK_CHANGED_EVENT, handler);\n sub.editor = ed;\n sub.handler = handler;\n bound.set(createBlocksApiForEditor(ed, touch));\n };\n\n // Run the initial binding SYNCHRONOUSLY so the returned facade is immediately\n // usable (Angular's effect() is deferred — it does not fire on the same tick).\n // This mirrors Vue's `watch(..., { immediate: true })`.\n bindToEditor(editor());\n\n // Re-bind when the editor identity changes. Angular 20 permits signal writes\n // inside effect() by default (allowSignalWrites option was removed in v20).\n effect(() => {\n bindToEditor(editor());\n });\n\n inject(DestroyRef).onDestroy(unsubscribe);\n\n // A stable facade whose methods delegate to the currently-bound API. Reading\n // `bound()` tracks the editor swap; shared reads track `version` via onRead.\n // Every key listed EXPLICITLY (no spread) so a forgotten delegation is a\n // COMPILE error against UseBlocksApi rather than a silently-missing method.\n return {\n getById: (id) => bound().getById(id),\n getChildren: (parentId) => bound().getChildren(parentId),\n insert: (spec) => bound().insert(spec),\n insertMany: (specs) => bound().insertMany(specs),\n insertTree: (spec) => bound().insertTree(spec),\n insertMarkdown: (markdown, options) => bound().insertMarkdown(markdown, options),\n exportMarkdown: () => bound().exportMarkdown(),\n move: (id, target) => bound().move(id, target),\n nest: (id, parentId) => bound().nest(id, parentId),\n unnest: (id) => bound().unnest(id),\n remove: (id) => bound().remove(id),\n update: (id, data, tunes) => bound().update(id, data, tunes),\n convert: (id, newType, dataOverrides, options) => bound().convert(id, newType, dataOverrides, options),\n transact: (fn) => bound().transact(fn),\n transactWithoutCapture: (fn) => bound().transactWithoutCapture(fn),\n getBlocksCount: () => bound().getBlocksCount(),\n getCurrentBlockIndex: () => bound().getCurrentBlockIndex(),\n getBlockByIndex: (index) => bound().getBlockByIndex(index),\n getBlockByElement: (element) => bound().getBlockByElement(element),\n getBlockData: (id) => bound().getBlockData(id),\n getBlockIndex: (id) => bound().getBlockIndex(id),\n composeBlockData: (toolName) => bound().composeBlockData(toolName),\n renderFromHTML: (html) => bound().renderFromHTML(html),\n insertOutputData: (blocks, options) => bound().insertOutputData(blocks, options),\n splitBlock: (currentBlockId, currentBlockData, newBlockType, newBlockData, insertIndex) =>\n bound().splitBlock(currentBlockId, currentBlockData, newBlockType, newBlockData, insertIndex),\n insertInsideParent: (parentId, insertIndex, childData) =>\n bound().insertInsideParent(parentId, insertIndex, childData),\n render: (data) => bound().render(data),\n clear: () => bound().clear(),\n isSyncingFromYjs: () => bound().isSyncingFromYjs(),\n };\n}\n","// packages/angular/src/useBlokReady.ts\nimport { DestroyRef, ElementRef, afterNextRender, inject, signal, type Signal } from '@angular/core';\n\nimport { Blok as BlokRuntime } from '@bloklabs/core';\n\n/** How the caller names the DOM scope to observe. */\nexport type BlokReadyScope =\n | (() => Element | ElementRef<Element> | null | undefined)\n | ElementRef<Element>\n | Element\n | null;\n\n/** Options accepted by {@link injectBlokReady}. */\nexport interface InjectBlokReadyOptions {\n /**\n * Restrict the wait to editors mounted inside this element. Accepts an\n * element, an `ElementRef`, or a getter/signal returning either — the getter\n * form lets you pass `() => this.scopeRef?.nativeElement` from a field\n * initializer, before the view exists. It is re-read on every readiness\n * change.\n *\n * Omit it to observe every editor on the page. Passing it while it still\n * resolves to null reports NOT ready — an unresolved scope must never fall\n * back to the page-global one.\n */\n within?: BlokReadyScope;\n /**\n * `'ready'` (default) settles when each editor has finished booting.\n * `'rendered'` also waits for its content to be in the DOM and re-arms on\n * every post-boot re-render.\n */\n settleOn?: 'ready' | 'rendered';\n}\n\n/**\n * Resolves the caller's scope description to an element, or null when it is\n * not available yet.\n * @param within - the scope description passed in options\n */\nfunction resolveScope(within: BlokReadyScope): Element | null {\n const value = typeof within === 'function' ? within() : within;\n\n if (value === null || value === undefined) {\n return null;\n }\n\n return value instanceof ElementRef ? value.nativeElement : value;\n}\n\n/**\n * Angular factory exposing the live readiness of the Blok editors in a DOM\n * scope as a boolean signal.\n *\n * The readiness logic itself is framework-agnostic and lives in core\n * (`Blok.readyState` / `Blok.subscribeReady`) — the SAME implementation behind\n * React's and Vue's `useBlokReady`, so the three adapters cannot drift. This\n * wrapper supplies only Angular's reactivity: a signal re-read on every\n * registry change, unsubscribed through the injector's `DestroyRef`.\n *\n * Call it in an injection context (component constructor / field initializer).\n * The signal starts `false` and takes its first real reading in\n * `afterNextRender` — browser-only by contract, and late enough for a\n * `@ViewChild` scope to exist. Over-waiting is safe; under-waiting is a bug.\n * @param options - scope and readiness depth\n */\nexport function injectBlokReady(options: InjectBlokReadyOptions = {}): Signal<boolean> {\n const { within, settleOn } = options;\n const ready = signal(false);\n\n const read = (): void => {\n const scope = within === undefined ? null : resolveScope(within);\n\n // A scope that was asked for but has not resolved yet is NOT the global\n // scope — reporting ready here would gate on the wrong set of editors.\n ready.set(within !== undefined && scope === null\n ? false\n : BlokRuntime.readyState({\n within: scope,\n settleOn,\n }).ready);\n };\n\n inject(DestroyRef).onDestroy(BlokRuntime.subscribeReady(read));\n afterNextRender(read);\n\n return ready.asReadonly();\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["BlokRuntime"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bloklabs-angular.mjs","names":["BlokRuntime","BlokRuntime"],"sources":["../../../../dist/.angular-build/angular/provide-blok.ts","../../../../dist/.angular-build/angular/block-context.ts","../../../../dist/.angular-build/angular/blok-instance.ts","../../../../dist/.angular-build/angular/block-portal-registry.ts","../../../../dist/.angular-build/angular/registry-map.ts","../../../../dist/.angular-build/angular/blok-content.directive.ts","../../../../dist/.angular-build/components/errors/tool-not-found.ts","../../../../dist/.angular-build/components/utils/host-preserved-data.ts","../../../../dist/.angular-build/components/utils/id-generator.ts","../../../../dist/.angular-build/shared/flatten-tree.ts","../../../../dist/.angular-build/components/utils/blocks-tree.ts","../../../../dist/.angular-build/components/utils/blocks-api.ts","../../../../dist/.angular-build/components/utils/readonly-config.ts","../../../../dist/.angular-build/shared/deep-equal.ts","../../../../dist/.angular-build/shared/output-data.ts","../../../../dist/.angular-build/shared/prop-schema.ts","../../../../dist/.angular-build/components/constants/data-attributes.ts","../../../../dist/.angular-build/components/utils/html.ts","../../../../dist/.angular-build/tools/nested-blocks.ts","../../../../dist/.angular-build/tools/child-decoration.ts","../../../../dist/.angular-build/components/events/BlockChildrenMounted.ts","../../../../dist/.angular-build/angular/blok-editor.component.ts","../../../../dist/.angular-build/angular/createAngularBlock.ts","../../../../dist/.angular-build/angular/useBlocks.ts","../../../../dist/.angular-build/angular/useBlokReady.ts"],"sourcesContent":["import {\n InjectionToken,\n makeEnvironmentProviders,\n type EnvironmentProviders,\n} from '@angular/core';\nimport type { BlokAngularConfig } from './types';\n\n/**\n * DI token holding app-wide Blok defaults (shared tools registry, default theme,\n * i18n). Merged under per-instance inputs by `BlokEditorComponent`.\n */\nexport const BLOK_DEFAULT_CONFIG = new InjectionToken<Partial<BlokAngularConfig>>(\n 'BLOK_DEFAULT_CONFIG'\n);\n\n/**\n * Standalone provider registering app-wide Blok defaults.\n *\n * @example\n * ```ts\n * bootstrapApplication(AppComponent, {\n * providers: [provideBlok({ theme: 'dark', tools: sharedTools })],\n * });\n * ```\n */\nexport function provideBlok(defaults: Partial<BlokAngularConfig>): EnvironmentProviders {\n return makeEnvironmentProviders([{ provide: BLOK_DEFAULT_CONFIG, useValue: defaults }]);\n}\n","import type { API, BlockAPI } from '@bloklabs/core';\n// packages/angular/src/block-context.ts\nimport { InjectionToken, type Signal } from '@angular/core';\n\n\n/**\n * One child's decoration: attribute name → value. `null`/`undefined` removes the\n * attribute; a boolean or number is stringified (so `false` writes\n * `data-active=\"false\"`, which CSS can select, rather than dropping the hook).\n */\nexport type ChildAttributes = Record<string, string | number | boolean | null | undefined>;\n\n/** The per-child decorator accepted by {@link AngularBlockRenderContext.mountChildren}. */\nexport type ChildAttributesFn = (child: BlockAPI, index: number) => ChildAttributes;\n\n/**\n * Context handed to a `createAngularBlock` component. Delivered via DI (the\n * BLOK_BLOCK_CONTEXT token) rather than @Input, because core constructs the tool\n * outside Angular and the signal-input() form does not compile under the repo's\n * JIT test harness. The ONLY data write path is `commit`.\n */\nexport interface AngularBlockRenderContext<Data> {\n /** Reactive, FROZEN snapshot of the block data. Read `data()`; never mutate. */\n data: Signal<Readonly<Data>>;\n /** The ONLY data write path: merge a partial patch and sync once. */\n commit: (patch: Partial<Data>) => void;\n /** This block's per-block API (id, getChildren, dispatchChange…). */\n block: BlockAPI;\n /**\n * The EDITOR-level API this block belongs to (`api.blocks`, `api.caret`,\n * `api.toolbar`…) — the same object a vanilla tool receives in its\n * constructor. Reach for it when a block has to drive the document around it\n * instead of routing everything through `block.call()` string dispatch.\n *\n * For the reactive, id/parentId-relative view of the tree (and to re-render\n * when your own children change), pair `injectBlocks` with\n * `injectBlokInstance()` instead — the api handle itself is not reactive.\n */\n api: API;\n /**\n * Reactive read-only flag. Read `readOnly()` in the template to disable\n * editing (drop `contenteditable`, hide controls). Toggled IN PLACE by core's\n * read-only switch — the component reacts without a remount, so ephemeral\n * state survives. A block that ignores it stays interactive when the editor is\n * read-only (same contract as a vanilla tool's `setReadOnly`).\n */\n readOnly: Signal<boolean>;\n /**\n * Container blocks only: append this block's real child holders into `host`\n * (a `data-blok-nested` element the author owns). Call it once in\n * `ngAfterViewInit`; the factory re-runs the same mount on every data change\n * so late-added children appear. Angular must NOT manage these child holders.\n *\n * `childAttributes` decorates each child's HOLDER after the holders are\n * mounted, and is REMEMBERED — every later remount re-applies it. Named hooks\n * (`data-step-index`, `data-active`…) replace positional `:nth-child()` CSS\n * over Blok's holders, which breaks the moment a child is inserted, removed or\n * reordered. The holders stay DIRECT children of `host` — core requires that\n * (hierarchy reparenting and caret navigation compare `holder.parentElement`\n * by identity), so decoration is attributes, never wrapper elements.\n * Attributes the callback stops producing are removed on the next pass.\n *\n * `childContentAttributes` is the same decoration applied one level IN — on\n * each child's `[data-blok-element-content]` wrapper instead of its holder —\n * and is remembered the same way. Core's decoration law blesses both, and a\n * container needs both: the holder is the child's outer box (rails, indices,\n * hover states), the content wrapper is where the child's own text box begins,\n * which is what a numbered rail or a connector line has to align to. Reach for\n * it instead of walking core's wrapper chain from a holder hook (`[data-step] >\n * [data-blok-element-content] > …`) — those selectors encode engine DOM in host\n * CSS and break when that structure changes. A child whose DOM has not\n * committed yet has no wrapper to write to and is stamped on the next pass.\n *\n * Writing on a child's holder is inert by design: core's mutation filter drops\n * a holder-targeted attribute record for the child block and suppresses it for\n * the container. The guarantee stops at the holder and its\n * `[data-blok-element-content]` wrapper — writing AT or BELOW a child's tool\n * root DOES score as that child's edit.\n */\n mountChildren: (\n host: HTMLElement,\n childAttributes?: ChildAttributesFn,\n childContentAttributes?: ChildAttributesFn\n ) => void;\n /**\n * Name the element the +/drag toolbar should vertically center on, from inside\n * the component: `ctx.setToolbarAnchor(this.head().nativeElement)` in\n * `ngAfterViewInit`. The Angular counterpart of React's/Vue's\n * `toolbarAnchorRef` — core's `getToolbarAnchorElement` is otherwise a\n * `(host, block) => Element` hook resolved OUTSIDE the component, so pointing\n * at an element the template renders meant inventing a data attribute and\n * `querySelector`-ing for it from\n * `CreateAngularBlockSpec.getToolbarAnchorElement`.\n *\n * A container block whose own chrome is not editable needs an anchor: with\n * none, core centers the toolbar on the first `[contenteditable]` under the\n * host, which for a container is its FIRST CHILD BLOCK — parking the +/drag\n * handles halfway down, beside content that has a toolbar of its own.\n *\n * The element set here outranks the declared hook while it is MOUNTED; once it\n * detaches (or `null` is passed) the hook takes over again, so the toolbar is\n * never positioned against a stale node. Never calling it keeps core's default.\n */\n setToolbarAnchor: (element: HTMLElement | null) => void;\n}\n\n/** DI token carrying the per-block render context into the authored component. */\nexport const BLOK_BLOCK_CONTEXT = new InjectionToken<AngularBlockRenderContext<unknown>>(\n 'BLOK_BLOCK_CONTEXT'\n);\n","import type { Blok } from '@bloklabs/core';\n// packages/angular/src/blok-instance.ts\nimport { inject, InjectionToken, signal, type Signal } from '@angular/core';\n\n\n/**\n * DI token carrying the LIVE editor instance (as a signal) into every block\n * mounted by `createAngularBlock`. `BlokContentDirective` publishes its own\n * `instance` signal through it, so the value is null before the editor is ready\n * and after teardown — matching the React/Vue adapters' pre-ready contract.\n *\n * Provided on the block's ELEMENT injector by the portal registry, so it is\n * per-EDITOR: two editors on one page each publish their own instance.\n */\nexport const BLOK_EDITOR_INSTANCE = new InjectionToken<Signal<Blok | null>>(\n 'BLOK_EDITOR_INSTANCE'\n);\n\n/** Stable \"no editor here\" signal for components mounted outside an editor. */\nconst NO_EDITOR: Signal<Blok | null> = signal(null).asReadonly();\n\n/**\n * The live Blok instance the component is mounted inside, as a signal, or a\n * signal of null before it exists. Inside a `createAngularBlock` component this\n * is the block's OWN editor — so a block can drive the tree it lives in without\n * the host prop-drilling the instance into it:\n *\n * ```ts\n * private readonly editor = injectBlokInstance();\n * private readonly blocks = injectBlocks(this.editor);\n * ```\n *\n * That pairing is also what makes a container block REACTIVE to its own child\n * tree: `injectBlocks` refreshes on the editor's `block changed` event, which\n * core emits for every structural mutation — including children the adapter\n * itself never sees (a pasted paragraph, a Tab-indent from the keyboard).\n *\n * Call it in an injection context (a field initializer or the constructor).\n * Outside an editor it returns a signal of null.\n */\nexport function injectBlokInstance(): Signal<Blok | null> {\n return inject(BLOK_EDITOR_INSTANCE, { optional: true }) ?? NO_EDITOR;\n}\n","import type { Blok } from '@bloklabs/core';\n// packages/angular/src/block-portal-registry.ts\nimport {\n ApplicationRef,\n createComponent,\n EnvironmentInjector,\n ErrorHandler,\n Injector,\n type ComponentRef,\n type Signal,\n type Type,\n} from '@angular/core';\n\n\nimport { BLOK_BLOCK_CONTEXT, type AngularBlockRenderContext } from './block-context';\nimport { BLOK_EDITOR_INSTANCE } from './blok-instance';\n\n/**\n * Tool-config key carrying the editor's portal registry into a\n * `createAngularBlock` tool. The tool is constructed by CORE (outside any Angular\n * injection context), so it cannot `inject()` — the directive injects the\n * editor-scoped registry through each Angular-block tool's `config`, and the tool\n * reads it back from there.\n */\nexport const BLOK_PORTAL_REGISTRY_CONFIG_KEY = '__blokAngularPortalRegistry';\n\n/** One mounted Angular block: the Blok-owned host the component renders into. */\nexport interface BlockPortalEntry {\n hostEl: HTMLElement;\n component: Type<unknown>;\n context: AngularBlockRenderContext<unknown>;\n}\n\n/**\n * Per-editor registry of Angular blocks. Mounts each authored component directly\n * into its core-owned host via `createComponent({ hostElement })` (the Teleport\n * analog) and enrolls it in `ApplicationRef` for change detection. A plain Map —\n * Angular has no reactive-proxy hazard, so no `markRaw` equivalent is needed.\n */\nexport interface BlockPortalRegistry {\n /** Mount (or replace) the component for `id` into `entry.hostEl`. */\n register(id: string, entry: BlockPortalEntry): void;\n /**\n * Detach + destroy the component for `id`. Safe (no-op) when absent.\n *\n * Pass the caller's own `hostEl` to make the teardown OWNERSHIP-CHECKED: the\n * mount is destroyed only when it is still the one that host registered. Core\n * composes a replacement block (which registers under the SAME id) BEFORE it\n * destroys the block it replaces, so a superseded tool's `removed()`/\n * `destroy()` teardown arrives after the live mount already exists — without\n * the check it destroys that live componentRef and clears its host.\n */\n unregister(id: string, hostEl?: HTMLElement): void;\n /** Re-run change detection on the block's component (in-place update). */\n flush(id: string): void;\n /** Detach + destroy every mounted block (editor teardown / recreate). */\n destroyAll(): void;\n}\n\n/**\n * Create a fresh portal registry bound to a live Angular environment. One per\n * editor instance (associated via the registry map). The injectors/appRef are\n * passed in (captured by the directive in an injection context) because the\n * registry itself is built outside one.\n *\n * `editor` is the directive's own instance signal. It is passed at CREATION\n * (before the editor exists) rather than set later precisely because it is a\n * signal: blocks mounted during boot read null and re-read the real instance\n * once it resolves.\n * @param envInjector - the app environment injector (parent of each block's)\n * @param appRef - the ApplicationRef each mounted block view is attached to\n * @param errorHandler - where a throwing author component is reported\n * @param editor - signal of the live Blok instance, published to blocks via\n * {@link BLOK_EDITOR_INSTANCE}; omit for registries with no editor to publish\n */\nexport const createBlockPortalRegistry = (\n envInjector: EnvironmentInjector,\n appRef: ApplicationRef,\n errorHandler: ErrorHandler,\n editor?: Signal<Blok | null>\n): BlockPortalRegistry => {\n const mounted = new Map<string, { ref: ComponentRef<unknown>; injector: Injector }>();\n\n // Change detection runs outside NgZone here; a throwing author component must\n // degrade to a blank holder, not break core's block insertion.\n const safe = (fn: () => void): void => {\n try {\n fn();\n } catch (error) {\n errorHandler.handleError(error);\n }\n };\n\n const teardown = (id: string, ownerHostEl?: HTMLElement): void => {\n const entry = mounted.get(id);\n\n if (entry === undefined) {\n return;\n }\n\n const { ref, injector } = entry;\n // Capture host before deletion so we can clear it below.\n const hostEl = ref.location.nativeElement as HTMLElement;\n\n // A superseded owner may not destroy the mount that replaced it.\n if (ownerHostEl !== undefined && hostEl !== ownerHostEl) {\n return;\n }\n\n mounted.delete(id);\n appRef.detachView(ref.hostView);\n ref.destroy();\n // `Injector.create({ parent })` returns an injector that is NOT torn down by\n // `ref.destroy()`. We must destroy it explicitly to prevent one small injector\n // accumulating per block over a long editor session.\n const destroyable = injector as Injector & { destroy?: () => void };\n destroyable.destroy?.();\n // createComponent({ hostElement }) renders INTO an external div. Angular's\n // destroy() tears down the component instance and CD but does NOT clear the\n // host's DOM children — we must do it explicitly.\n hostEl.replaceChildren();\n };\n\n return {\n register(id: string, entry: BlockPortalEntry): void {\n // Idempotent: replace any prior mount for this id.\n teardown(id);\n\n // The context is provided through an ELEMENT injector (a node injector),\n // so it is destroyed automatically with the component view — no leaked\n // EnvironmentInjector. The shared app envInjector is the parent, so author\n // blocks still see app-level providers (HttpClient, etc.).\n const elementInjector = Injector.create({\n providers: [\n { provide: BLOK_BLOCK_CONTEXT, useValue: entry.context },\n // Per-EDITOR, so two editors on one page each publish their own\n // instance to their own blocks.\n ...(editor === undefined\n ? []\n : [{ provide: BLOK_EDITOR_INSTANCE, useValue: editor }]),\n ],\n parent: envInjector,\n });\n\n safe(() => {\n const ref = createComponent(entry.component, {\n environmentInjector: envInjector,\n elementInjector,\n hostElement: entry.hostEl,\n });\n\n appRef.attachView(ref.hostView);\n mounted.set(id, { ref, injector: elementInjector });\n // createComponent does not auto-run CD; render synchronously into the\n // (still-detached) host before core inserts it into the document.\n ref.changeDetectorRef.detectChanges();\n });\n },\n unregister(id: string, hostEl?: HTMLElement): void {\n teardown(id, hostEl);\n },\n flush(id: string): void {\n const entry = mounted.get(id);\n\n if (entry === undefined) {\n return;\n }\n\n safe(() => entry.ref.changeDetectorRef.detectChanges());\n },\n destroyAll(): void {\n for (const id of Array.from(mounted.keys())) {\n teardown(id);\n }\n },\n };\n};\n","// packages/angular/src/registry-map.ts\nimport type { BlockPortalRegistry } from './block-portal-registry';\n\n/**\n * Associates each live Blok instance with its portal registry. `BlokContentDirective`\n * sets it at creation so consumers (and future composables) can reach an editor's\n * registry. WeakMap → no leak when the editor is destroyed.\n */\nconst registries = new WeakMap<WeakKey, BlockPortalRegistry>();\n\nexport function setRegistry(editor: WeakKey, registry: BlockPortalRegistry): void {\n registries.set(editor, registry);\n}\n\nexport function getRegistry(editor: WeakKey): BlockPortalRegistry | undefined {\n return registries.get(editor);\n}\n\nexport function removeRegistry(editor: WeakKey): void {\n registries.delete(editor);\n}\n","import {\n Directive,\n ElementRef,\n EventEmitter,\n NgZone,\n Output,\n PLATFORM_ID,\n Input,\n ApplicationRef,\n EnvironmentInjector,\n ErrorHandler,\n afterNextRender,\n inject,\n signal,\n type OnDestroy,\n} from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n// Imported via the package's public specifier so ng-packagr externalizes the\n// core as a peer dependency (consumers share a single Blok instance + CSS).\nimport { Blok as BlokRuntime, type Blok } from '@bloklabs/core';\nimport { BLOK_DEFAULT_CONFIG } from './provide-blok';\nimport type { BlokAngularConfig } from './types';\nimport {\n BLOK_PORTAL_REGISTRY_CONFIG_KEY,\n createBlockPortalRegistry,\n type BlockPortalRegistry,\n} from './block-portal-registry';\nimport { removeRegistry, setRegistry } from './registry-map';\n\n/**\n * The `collaboration` config each live editor was CONSTRUCTED with, keyed by the\n * editor itself. Written in `build()` from the very object handed to\n * `new BlokRuntime`, so a later `[config]` rebuild cannot change the answer —\n * `collaboration` is mount-fixed, and a host that drops the key from `[config]`\n * is still driving a live collaborative session.\n *\n * WeakMap → no leak when the editor is destroyed.\n */\nconst constructedCollaborations = new WeakMap<WeakKey, BlokAngularConfig['collaboration']>();\n\n/**\n * The `collaboration` the given editor was constructed with.\n * @param editor - a Blok instance built by `BlokContentDirective`\n * @returns the mount-time collaboration config, `undefined` when there was none\n */\nexport function getConstructedCollaboration(editor: WeakKey): BlokAngularConfig['collaboration'] {\n return constructedCollaborations.get(editor);\n}\n\n/**\n * Escape-hatch directive and lifecycle engine for Blok (mirrors React's\n * `useBlok` + `BlokContent`). Constructs a Blok instance into its own host\n * element and tears it down on destroy.\n *\n * The editor renders directly into the directive's host element — so the host\n * IS the holder. This sidesteps the fact that Blok core exposes no public\n * `holder` accessor: the adapter never has to read it back, it owns it.\n *\n * `BlokEditorComponent` applies this directive to its internal `<div>` and reads\n * the instance back; consumers can also use it directly for full control:\n * `<div blokContent [config]=\"cfg\" (ready)=\"onReady($event)\"></div>`.\n *\n * Implementation note: classic `@Input()`/`@Output()` are used (not signal\n * `input()`/`output()`) because the repo's Vitest+Analog harness compiles the\n * adapter via JIT, which does not register signal-based members. `instance`\n * remains a plain `signal` (runtime API, JIT-safe) for reactive consumption.\n */\n@Directive({\n selector: '[blokContent]',\n standalone: true,\n})\nexport class BlokContentDirective implements OnDestroy {\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly ngZone = inject(NgZone);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n /**\n * App-wide defaults from `provideBlok()`, merged UNDER the bound `[config]` so\n * the escape-hatch path honors them just like `<blok-editor>` (which also\n * merges, idempotently). Mirrors React's `useBlok` merging context defaults.\n */\n private readonly defaults = inject(BLOK_DEFAULT_CONFIG, { optional: true }) ?? {};\n // Captured in the injection context (field initializers) so the registry can\n // mount author components via createComponent — core constructs tools outside\n // Angular DI and cannot inject these itself.\n private readonly envInjector = inject(EnvironmentInjector);\n private readonly appRef = inject(ApplicationRef);\n private readonly errorHandler = inject(ErrorHandler);\n\n /** Construction-time Blok config (everything except `holder`, which the directive owns). */\n @Input() config: Partial<BlokAngularConfig> = {};\n\n /** Changing this input's identity (after the first build) destroys + recreates the editor. */\n @Input() set recreateKey(value: unknown) {\n const changed = this.built && value !== this.currentKey;\n this.currentKey = value;\n\n if (changed) {\n this.current?.destroy();\n this.build();\n }\n }\n\n /** Emits the live Blok instance once it is ready, after `instance` is populated. */\n @Output() readonly ready = new EventEmitter<Blok>();\n\n /** The live Blok instance, or null before `isReady` resolves / after destroy. */\n readonly instance = signal<Blok | null>(null);\n\n /** The editor created by the most recent construction; used as the staleness key. */\n private current: Blok | null = null;\n private destroyed = false;\n private built = false;\n private currentKey: unknown;\n /** The portal registry for the current editor (Angular-block mounting). */\n private registry: BlockPortalRegistry | undefined;\n\n constructor() {\n // afterNextRender is browser-only (skipped during SSR) and runs after the\n // host element exists and inputs are bound.\n afterNextRender(() => {\n // afterNextRender is browser-only by contract, but guard explicitly so the\n // editor is never constructed during SSR / on a non-browser platform.\n if (this.destroyed || !this.isBrowser) {\n return;\n }\n\n this.build();\n this.built = true;\n });\n }\n\n /** Construct a Blok into the host element and publish it once ready. */\n private build(): void {\n this.destroyed = false;\n this.instance.set(null);\n\n // Tear down any registry from a superseded editor (recreate path) before\n // building a new one.\n this.registry?.destroyAll();\n\n // Merge provideBlok defaults under the bound config (instance wins; tools\n // registries compose across both layers rather than replacing).\n const merged: Partial<BlokAngularConfig> = { ...this.defaults, ...this.config };\n\n if (this.defaults.tools !== undefined || this.config.tools !== undefined) {\n merged.tools = { ...this.defaults.tools, ...this.config.tools };\n }\n\n // Create the editor-scoped portal registry and thread it into every\n // Angular-block tool's config (vanilla tools pass through untouched).\n // `this.instance` is handed over at creation: it is a SIGNAL, so blocks\n // mounted during boot read null and re-read the real editor once isReady\n // resolves — no ordering problem, and `injectBlokInstance()` inside a block\n // component tracks the swap.\n const registry = createBlockPortalRegistry(\n this.envInjector,\n this.appRef,\n this.errorHandler,\n this.instance\n );\n\n this.registry = registry;\n merged.tools = injectPortalRegistry(merged.tools, registry);\n\n // Construct outside Angular's zone so the editor's internal DOM churn never\n // schedules change detection.\n const blok = this.ngZone.runOutsideAngular(\n () =>\n new BlokRuntime({\n ...merged,\n holder: this.host.nativeElement,\n }) as unknown as Blok\n );\n\n this.current = blok;\n // Captured from `merged` — the exact object this editor was built from —\n // rather than re-read later from `this.config`, which the host may have\n // rebuilt by then. See `constructedCollaborations`.\n constructedCollaborations.set(blok, merged.collaboration);\n setRegistry(blok, registry);\n\n void blok.isReady.then(() =>\n this.ngZone.run(() => {\n // Guard on the constructor-returned reference (not isReady's resolved\n // value): a superseded or torn-down editor must not publish itself.\n if (this.current !== blok || this.destroyed) {\n return;\n }\n\n this.instance.set(blok); // assign FIRST…\n this.ready.emit(blok); // …THEN emit, so consumers see a populated instance.\n })\n );\n }\n\n ngOnDestroy(): void {\n this.destroyed = true;\n this.registry?.destroyAll();\n\n if (this.current !== null) {\n removeRegistry(this.current);\n }\n\n this.current?.destroy();\n this.current = null;\n this.registry = undefined;\n this.instance.set(null);\n }\n}\n\n/**\n * Return a NEW tools map (never mutate the consumer's config) where each\n * Angular-block tool carries the portal registry under\n * BLOK_PORTAL_REGISTRY_CONFIG_KEY in its `config`. Vanilla tools are returned\n * unchanged. Handles both entry shapes: a bare constructor and `{ class, config }`.\n */\nfunction injectPortalRegistry(\n tools: BlokAngularConfig['tools'],\n registry: BlockPortalRegistry\n): BlokAngularConfig['tools'] {\n if (tools === undefined) {\n return tools;\n }\n\n const result: Record<string, unknown> = {};\n\n for (const [name, entry] of Object.entries(tools)) {\n const asObject = entry as { class?: unknown; config?: Record<string, unknown> } | undefined;\n const toolClass = (typeof entry === 'function' ? entry : asObject?.class) as\n | { __isBlokAngularBlock?: boolean }\n | undefined;\n\n if (toolClass?.__isBlokAngularBlock === true) {\n const base = typeof entry === 'function' ? { class: entry } : { ...asObject };\n\n result[name] = {\n ...base,\n config: { ...(base.config ?? {}), [BLOK_PORTAL_REGISTRY_CONFIG_KEY]: registry },\n };\n } else {\n result[name] = entry;\n }\n }\n\n return result as BlokAngularConfig['tools'];\n}\n","/**\n * Thrown when a block tool cannot be resolved during a creation/conversion\n * operation (insert, insertMany/composeBlock, composeBlockData, convert).\n *\n * A typed error lets adapters (React/Vue/Angular useBlocks) distinguish a\n * genuinely-unknown tool — an EXPECTED, recoverable outcome they surface as a\n * `null`/`[]` no-op — from a real bug, WITHOUT brittle `message.includes('not\n * found')` substring matching (which both mis-catches unrelated errors whose\n * message happens to contain \"not found\" and breaks under message localization).\n */\nexport class ToolNotFoundError extends Error {\n /**\n * @param toolName - the tool type that could not be resolved\n * @param message - optional override; defaults to a descriptive message\n */\n constructor(public readonly toolName: string, message?: string) {\n super(message ?? `Block Tool «${toolName}» not found.`);\n this.name = 'ToolNotFoundError';\n }\n}\n","/**\n * Key of a hidden BlockAPI method that returns `preservedData` the way hosts\n * receive it (segments). Not published: the\n * adapters' `getBlockData` reads it and falls back to `preservedData` when\n * absent. `Symbol.for` because the adapters can be bundled apart from core.\n */\nexport const HOST_PRESERVED_DATA: unique symbol = Symbol.for('blok.hostPreservedData');\n","/**\n * ID generation utilities\n */\n\n// nanoid replaced with inline crypto implementation for the Angular adapter bundle.\nconst _ID_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-';\nconst _nanoid = (n: number): string => {\n const buf = crypto.getRandomValues(new Uint8Array(n));\n return Array.from(buf, (b) => _ID_CHARS[b % 64]).join('');\n};\nconst nanoid = _nanoid;\n\n/**\n * Constants for ID generation\n */\nconst ID_RANDOM_MULTIPLIER = 100_000_000; // 1e8\nconst HEXADECIMAL_RADIX = 16;\n\n/**\n * Create a block id\n * @returns unique block ID\n */\nexport const generateBlockId = (): string => {\n const idLen = 10;\n\n return nanoid(idLen);\n};\n\n/** A document id. nanoid, not crypto.randomUUID: that one is missing outside secure contexts. */\nexport const generateDocumentId = (): string => nanoid(21);\n\n/**\n * Nanoid-compatible block ID pattern: exactly 10 URL-safe characters (A-Z, a-z, 0-9, _, -)\n */\nconst BLOCK_ID_PATTERN = /^[A-Za-z0-9_-]{10}$/;\n\n/**\n * Returns true if the given string is a valid block ID (nanoid format).\n * @param id - string to check\n */\nexport const isValidBlockId = (id: string): boolean => BLOCK_ID_PATTERN.test(id);\n\n/**\n * Returns random generated identifier\n * @param prefix - identifier prefix\n * @returns unique identifier with prefix\n */\nexport const generateId = (prefix = ''): string => {\n return `${prefix}${(Math.floor(Math.random() * ID_RANDOM_MULTIPLIER)).toString(HEXADECIMAL_RADIX)}`;\n};\n","import type { OutputBlockData, BlockId, BlockRunSpec, BlockTreeNode, BlockTreeSpec, FlattenTreeOptions } from '@bloklabs/core';\nimport { generateBlockId } from '../components/utils/id-generator';\n\n/** A flattened block with its `id` resolved (generated when the spec omitted one). */\ntype FlattenedBlock = OutputBlockData & { id: BlockId };\n\n/**\n * Whether a spec node is a pre-flat run (`{ blocks: [...] }`) rather than a\n * tree node. Keyed on the `blocks` array, the only field the two shapes cannot\n * share.\n * @param node - spec node to classify\n */\nconst isRunSpec = (node: BlockTreeNode): node is BlockRunSpec => {\n return Array.isArray((node as BlockRunSpec).blocks);\n};\n\n/**\n * Wire-tolerant id read: `null` and `''` mean \"absent\", as everywhere else a\n * loaded document is normalized.\n * @param id - id as it arrived on a saved block\n */\nconst nonEmptyId = (id: string | null | undefined): string | undefined => {\n return typeof id === 'string' && id !== '' ? id : undefined;\n};\n\n/**\n * Reject an already-flat block passed where a TREE node is expected. A spec\n * node has no `parent`/`content` fields, so such a block would be flattened\n * with its links silently DROPPED — the structure it described is gone and\n * nothing reports it. Pre-flat blocks belong in a run node instead.\n * @param node - tree node about to be flattened\n * @throws if the node carries link information a tree node cannot express\n */\nconst assertNotPreFlat = (node: BlockTreeSpec): void => {\n const asFlat = node as OutputBlockData;\n const carriesParent = typeof asFlat.parent === 'string' && asFlat.parent !== '';\n const carriesContent = Array.isArray(asFlat.content) && asFlat.content.length > 0;\n\n if (carriesParent || carriesContent) {\n throw new Error(\n `flattenTree: block \"${node.id ?? '(no id)'}\" carries \\`parent\\`/\\`content\\` links, which a tree node cannot express — pass pre-flat blocks as a run node: { blocks: [...] }.`\n );\n }\n};\n\n/**\n * Flatten a hierarchical block spec (nodes with `children`) into the flat DFS\n * pre-order `OutputBlockData[]` Blok stores, wiring every node's `parent` and\n * `content` id links.\n *\n * This is the pure counterpart of the live `insertTree` mutation: the same DFS,\n * without an editor. Use it to seed nested content — columns, tables, a whole\n * document — without hand-authoring `parent`/`content` arrays:\n *\n * @example\n * new Blok({\n * data: {\n * blocks: flattenTree([\n * { type: 'column_list', children: [\n * { type: 'column', children: [{ type: 'paragraph', data: { text: 'L' } }] },\n * { type: 'column', children: [{ type: 'paragraph', data: { text: 'R' } }] },\n * ] },\n * ]),\n * },\n * });\n *\n * Content that is not tree-shaped to begin with — an already-flat saved\n * document a migration is splicing into a page — goes in as a RUN node,\n * `{ blocks: [...] }`, at the root or as a child. A run is spliced verbatim:\n * ids, `data`, `tunes` and existing `parent`/`content` links are kept, and only\n * the blocks it left un-parented are re-parented onto the enclosing node.\n *\n * @example\n * flattenTree({ type: 'column', children: [{ blocks: saved.blocks }] });\n *\n * @param spec - a single root node or an array of root nodes; each is either a\n * tree node or a pre-flat run.\n * @param options - `parentId` sets the `parent` of the root node(s);\n * `generateId` overrides id generation for nodes that omit an `id` (default:\n * Blok's nanoid scheme).\n * @returns DFS pre-order blocks with `parent`/`content` wired. Leaves omit the\n * empty `content` array, matching the documented `OutputBlockData` shape.\n * @throws if an explicit `id` is reused within the spec — a duplicate id would\n * corrupt every id-keyed lookup, so it is surfaced loudly rather than encoded\n * — or if a TREE node carries `parent`/`content` links, which it cannot\n * express (that is a pre-flat block; wrap it in a run node).\n */\nexport function flattenTree(\n spec: BlockTreeNode | BlockTreeNode[],\n options: FlattenTreeOptions = {}\n): FlattenedBlock[] {\n const generateId = options.generateId ?? generateBlockId;\n const rootParent = options.parentId ?? undefined;\n\n const flat: FlattenedBlock[] = [];\n const usedIds = new Set<string>();\n\n /**\n * Resolve a node's id and reserve it. A duplicate would corrupt every\n * id-keyed lookup, so it is surfaced loudly rather than encoded.\n * @param explicitId - id the spec carried, if any\n */\n const claimId = (explicitId: string | undefined): string => {\n const id = explicitId ?? generateId();\n\n if (usedIds.has(id)) {\n throw new Error(`flattenTree: duplicate block id \"${id}\" — every block id must be unique.`);\n }\n usedIds.add(id);\n\n return id;\n };\n\n /**\n * Splice a pre-flat run in verbatim: every block keeps its id, `data`,\n * `tunes` and its existing `parent`/`content` links, and only the blocks the\n * run left un-parented are re-parented onto the enclosing node. Mirrors\n * `useBlocks.insertMarkdown`, which nests a converted run the same way.\n * @param run - the run node\n * @param parent - id of the node the run is spliced into (undefined at root)\n * @returns ids of the run's top-level blocks, in run order\n */\n const visitRun = (run: BlockRunSpec, parent: string | undefined): string[] => {\n const rootIds: string[] = [];\n\n for (const block of run.blocks) {\n const { parent: incomingParent, id: incomingId, content: incomingContent, data, ...rest } = block;\n const id = claimId(nonEmptyId(incomingId));\n const incomingParentId = nonEmptyId(incomingParent);\n const isRunRoot = incomingParentId === undefined;\n const resolvedParent = isRunRoot ? parent : incomingParentId;\n\n flat.push({\n ...rest,\n id,\n data: data ?? {},\n // `null`/`[]` content means \"no children\" — omitted, like a tree leaf.\n ...(Array.isArray(incomingContent) && incomingContent.length > 0 ? { content: incomingContent } : {}),\n ...(resolvedParent !== undefined ? { parent: resolvedParent } : {}),\n });\n\n if (isRunRoot) {\n rootIds.push(id);\n }\n }\n\n return rootIds;\n };\n\n // Pre-order DFS: push self FIRST, then recurse each child, so the flat array\n // is DFS-contiguous. `content` is filled as each child is visited and returns\n // its id; it is omitted for leaves.\n const visit = (node: BlockTreeSpec, parent: string | undefined): string => {\n assertNotPreFlat(node);\n\n const id = claimId(node.id);\n\n const childIds: string[] = [];\n const flatNode = {\n id,\n // `type` is OMITTED (not present-with-undefined) when absent so core's\n // `type || defaultBlock` fallback resolves the default block cleanly.\n ...(node.type !== undefined ? { type: node.type } : {}),\n data: node.data ?? {},\n ...(node.tunes !== undefined ? { tunes: node.tunes } : {}),\n ...(parent !== undefined ? { parent } : {}),\n } as FlattenedBlock;\n\n flat.push(flatNode);\n\n for (const child of node.children ?? []) {\n childIds.push(...(isRunSpec(child) ? visitRun(child, id) : [visit(child, id)]));\n }\n\n // Only wire `content` when there are children — leaves stay clean.\n if (childIds.length > 0) {\n flatNode.content = childIds;\n }\n\n return id;\n };\n\n const roots = Array.isArray(spec) ? spec : [spec];\n\n for (const root of roots) {\n if (isRunSpec(root)) {\n visitRun(root, rootParent);\n } else {\n visit(root, rootParent);\n }\n }\n\n return flat;\n}\n","import type { BlockToolData, BlockPosition, BlockTuneData, OutputBlockData, OutputData, MarkdownImportConfig } from '@bloklabs/core';\n\n/**\n * Where to place the caret within a block. `position` selects the input\n * (`'start'`/`'end'`/`'default'`) and `offset` is the character offset within it\n * — the same shape core's `caret.setToBlock` accepts.\n */\nexport interface CaretTarget {\n position?: 'start' | 'end' | 'default';\n offset?: number;\n}\n\n/**\n * A plain, serializable view of one block in the tree.\n *\n * Snapshot-volatile: every read allocates a fresh `BlockNode`, and `contentIds`\n * is DERIVED per read from the children that currently name this block as parent\n * (it is not a stored field). Read a node in render and re-read after a change —\n * don't stash one in a `useMemo`/`useEffect` dependency array expecting stable\n * identity; depend on the `id` instead.\n */\nexport interface BlockNode {\n id: string;\n type: string;\n parentId: string | null;\n contentIds: readonly string[];\n}\n\n/** Where to place a block among its siblings. */\nexport type InsertPosition = BlockPosition;\n\nexport interface InsertSpec {\n type?: string;\n data?: BlockToolData;\n parentId?: string | null;\n position?: InsertPosition;\n /**\n * Move the caret into the new block. Defaults to `false`: a programmatic\n * insert from React must not steal focus from wherever the user is typing.\n * Set `true` for an explicit \"add a block and start editing it\" flow.\n */\n focus?: boolean;\n /**\n * Replace the block at the resolved slot instead of inserting a new one — a\n * programmatic \"turn into\". Combine with a `position` that targets the block\n * to replace, e.g. `{ position: { before: id }, replace: true }`.\n */\n replace?: boolean;\n /**\n * Explicit id for the new block (generated when omitted). Passing a stable id\n * makes the insert idempotent: if a block with this id already exists the\n * existing node is returned and nothing is inserted (\"insert if absent\"),\n * so an effect that re-runs won't create duplicates.\n */\n id?: string;\n /** Block tune data to apply at creation, keyed by tune name. */\n tunes?: { [name: string]: BlockTuneData };\n /**\n * Place the caret inside the newly-created block at a specific position/offset\n * (e.g. `{ offset: 3 }`). Implies focus. Applied ONLY when a block is actually\n * created — an insert-if-absent hit (existing id) does not move the caret.\n * Use this instead of the boolean `focus` when you need a specific offset.\n */\n caret?: CaretTarget;\n}\n\n/**\n * One node of a pre-built nested subtree for {@link UseBlocksApi.insertTree}.\n *\n * Each node maps to one block; `children` are inserted nested under it (their\n * `parentId` set to this node's id) in array order, recursively. Placement\n * options (`parentId`/`position`) are ROOT-ONLY — they position the whole\n * subtree among existing blocks and are ignored on nested children, whose parent\n * is always their enclosing node.\n */\nexport interface TreeInsertSpec {\n type?: string;\n data?: BlockToolData;\n tunes?: { [name: string]: BlockTuneData };\n /**\n * Explicit id for this node (generated when omitted). Unlike `insert`, this is\n * NOT insert-if-absent: a tree insert always creates fresh blocks. A colliding\n * id — one that already exists in the document, or is reused by another node\n * in the same spec — is REJECTED up front: nothing is inserted and `insertTree`\n * returns `null` (a duplicate id would corrupt every id-keyed lookup).\n */\n id?: string;\n /** Direct children, inserted nested under this node, in array order. */\n children?: TreeInsertSpec[];\n /** Root-only: where to place the whole subtree. Ignored on nested children. */\n parentId?: string | null;\n /** Root-only: slot among siblings of `parentId`. Ignored on nested children. */\n position?: InsertPosition;\n}\n\n/**\n * Where to move an existing block.\n *\n * `before`/`after` make the block a sibling of the ref: it takes the ref's\n * parent. Moving a nested block to `{ after: someRootBlock }` therefore unnests\n * it to root, and moving a root block next to a container's child nests it.\n * Use `nest`/`unnest` when you want to change the parent without choosing a\n * sibling slot. `toIndex` is an absolute flat index (clamped into range).\n */\nexport type MoveTarget = { before: string } | { after: string } | { toIndex: number };\n\nexport interface UseBlocksApi {\n getById(id: string): BlockNode | null;\n getChildren(parentId: string | null): BlockNode[];\n /**\n * Insert one block; returns the created node or null when rejected (unknown\n * tool type, dangling `parentId`, or a `replace` whose target is missing). An\n * explicit `id` that already exists is insert-if-absent (returns the existing\n * node, creates nothing). Atomic — one undo step. The returned node is\n * {@link BlockNode}-volatile; read it now, don't put it in a dep array.\n */\n insert(spec?: InsertSpec): BlockNode | null;\n /**\n * Insert several blocks atomically, in array order, as ONE undo step. Each\n * spec is a full {@link InsertSpec} (own type/data/parentId/position), routed\n * through the same single-`insert` path, so per-spec parent assertion and\n * positioning still apply. Specs that fail to insert (e.g. a dangling\n * parentId, or a replace whose target is missing) are dropped; the returned\n * array holds only the successfully created nodes. An empty input is a no-op\n * (returns `[]`, opens no transaction). Like `insert`, the returned nodes are\n * fresh-snapshot volatile — read them now, don't stash them in dep arrays.\n */\n insertMany(specs: InsertSpec[]): BlockNode[];\n /**\n * Insert a pre-built NESTED subtree in ONE atomic operation (one undo step).\n * Each {@link TreeInsertSpec} node becomes a block; its `children` are inserted\n * nested under it (recursively, in array order) so the whole hierarchy lands in\n * a single call — no follow-up `nest` round-trips. Delegates to core's\n * tree-aware `blocks.insertMany`, which composes the flat DFS pre-order array\n * honoring each node's `parent`/`content` links.\n *\n * Placement is root-only: the root node's `parentId`/`position` position the\n * whole subtree among existing blocks (default: appended at the document end);\n * nested children ignore those fields (their parent is their enclosing node). A\n * dangling root `parentId` is rejected — nothing is inserted and `null` is\n * returned (mirrors {@link insert}). Returns the root {@link BlockNode}, which\n * is fresh-snapshot volatile — read it now, don't stash it in a dep array.\n */\n insertTree(spec: TreeInsertSpec): BlockNode | null;\n /**\n * Convert a Markdown string to blocks and insert them ADDITIVELY at a\n * position, WITHOUT clearing the document (unlike core's `importMarkdown` /\n * `renderFromHTML`, which replace the whole document). This is the React\n * \"paste markdown → blocks appear\" path.\n *\n * Async: the markdown converter is lazy-loaded (kept out of the main bundle),\n * so this is the ONE async creator in the API — `await` the returned promise.\n * The whole batch is inserted as a single atomic undo step.\n *\n * `position` (default `'end'`) places the converted run among `parentId`'s\n * children (or root siblings when `parentId` is omitted/null), reusing the\n * same `start`/`end`/`before`/`after` semantics as {@link insert}.\n *\n * `parentId` (default `null` = root) nests the import: every TOP-LEVEL\n * converted block (one the converter left un-parented) is reparented under\n * `parentId`, while blocks the markdown nested internally (e.g. table-cell\n * children) keep their intra-import parent. A dangling `parentId` is a no-op\n * (returns `[]`, opens no transaction), matching {@link insert}.\n *\n * `config` (optional {@link MarkdownImportConfig}) is forwarded to the\n * converter so custom-tool consumers can map markdown nodes into their tools\n * (`toolMap`/`onUnknownNode`), toggle GFM, or add micromark/mdast extensions.\n *\n * Returns ALL created {@link BlockNode}s in document order — including any the\n * markdown nested internally (e.g. a table's cell children), not just the\n * top-level run (this differs from {@link insertTree}, which returns only the\n * root). Empty or whitespace-only markdown, a dangling `parentId` (checked\n * again after the async convert, so a parent removed mid-flight also no-ops),\n * and a converter failure (chunk-load or parse error, swallowed) all return\n * `[]` and open no transaction. The nodes are fresh-snapshot volatile — read\n * them now, don't stash them in dep arrays.\n */\n insertMarkdown(\n markdown: string,\n options?: { parentId?: string | null; position?: InsertPosition; config?: MarkdownImportConfig }\n ): Promise<BlockNode[]>;\n /**\n * Serialize the WHOLE document to a Markdown string — the outbound twin of\n * core's `blocks.exportMarkdown` (and the read-side counterpart of the\n * additive {@link insertMarkdown}). Async: the serializer is lazy-loaded, like\n * the importer. Markdown cannot express every block, so some structure is\n * dropped (table `colspan`/`rowspan`, heading columns). Returns `''` for an\n * empty document. Pre-ready: resolves to `''`.\n */\n exportMarkdown(): Promise<string>;\n move(id: string, target: MoveTarget): void;\n nest(id: string, parentId: string): void;\n unnest(id: string): void;\n remove(id: string): void;\n /**\n * Update a block's data and/or tunes by id. Delegates to core's async\n * `blocks.update`, which forms its OWN undo step — the call is NOT wrapped in\n * `transact` (that would close the group before the async write lands). An\n * unknown id is a silent no-op; a rejected update is swallowed so it can't\n * surface as an unhandled rejection. Reads refresh reactively once core emits\n * 'block changed'. Returns `void`.\n */\n update(id: string, data?: BlockToolData, tunes?: { [name: string]: BlockTuneData }): void;\n /**\n * Convert a block to another type (\"turn into\") by id. Delegates to core's\n * async `blocks.convert`; both tools must provide a `conversionConfig` or core\n * rejects — that rejection (and any other) is swallowed so a non-convertible\n * block is a graceful no-op rather than an unhandled rejection. An unknown id\n * is a silent no-op. Not wrapped in `transact` (core owns its history step).\n * Returns `void`.\n */\n convert(\n id: string,\n newType: string,\n dataOverrides?: BlockToolData,\n options?: { caret?: CaretTarget }\n ): void;\n transact(fn: () => void): void;\n /**\n * Run `fn` as one atomic operation that is NOT captured in the undo history —\n * the React-surface counterpart of core's `transactWithoutCapture`. Use for\n * silent auto-repair/normalization that a user's CMD+Z should never step\n * through. Mutations inside still emit reactively. Pre-ready it just runs `fn`.\n *\n * With `options`, the operations are data worked out from the `from` keys of\n * block `derivedFrom` (a finished upload, for example): they join the undo\n * entry that wrote those values, as in core.\n */\n transactWithoutCapture(fn: () => void, options?: { derivedFrom?: string; from?: readonly string[] }): void;\n /**\n * The current block count. Reactive (re-reads on 'block changed'). Pre-ready: 0.\n */\n getBlocksCount(): number;\n /**\n * The flat index of the block holding the caret, or -1 when none. Pre-ready: -1.\n */\n getCurrentBlockIndex(): number;\n /** The block at a flat index as a snapshot {@link BlockNode}, or null. */\n getBlockByIndex(index: number): BlockNode | null;\n /**\n * The absolute flat index of a block by id, or null when unknown. The\n * counterpart to {@link getBlockByIndex} — use it to target an off-caret\n * {@link splitBlock} (whose `insertIndex` is absolute) without the ref. Unknown\n * ids return null silently (no console warn). Pre-ready: null.\n */\n getBlockIndex(id: string): number | null;\n /**\n * Read a block's current `data` and `tunes` by id WITHOUT mutating anything —\n * the synchronous last-extracted view (the same snapshot clipboard ops use).\n * Makes a client-side duplicate composable from the hook alone: read a node,\n * then `insert({ type, data, tunes, position })`, no ref escape hatch. Unknown\n * id returns null. Pre-ready: null.\n */\n getBlockData(id: string): { data: BlockToolData; tunes: { [name: string]: BlockTuneData } } | null;\n /**\n * The block whose holder contains/equals `element`, as a snapshot\n * {@link BlockNode}, or null. Useful for mapping a DOM event target back to a\n * block.\n */\n getBlockByElement(element: HTMLElement): BlockNode | null;\n /**\n * Read a tool's default empty data WITHOUT inserting anything — delegates to\n * core's `composeBlockData`. Async (a tool's data may be composed lazily).\n * Rejects (via core) for an unknown tool. Pre-ready: resolves to `{}`.\n */\n composeBlockData(toolName: string): Promise<BlockToolData>;\n /**\n * Replace the WHOLE document with blocks parsed from an HTML string —\n * delegates to core's `renderFromHTML`. Unlike {@link insertMarkdown} (which is\n * additive), this CLEARS existing content first, so it's a document-load\n * primitive, not an insert. Async. Pre-ready: resolves immediately (no-op).\n */\n renderFromHTML(html: string): Promise<void>;\n /**\n * Insert a flat array of already-serialized {@link OutputBlockData} (the\n * `save()` shape) directly, honoring each block's `parent`/`content` links —\n * the raw counterpart of core's `blocks.insertMany`. Use to re-insert a saved\n * document fragment without reshaping it into {@link TreeInsertSpec}. One\n * atomic undo step. Returns the created nodes; pre-ready: `[]` (no insert).\n */\n insertOutputData(blocks: OutputBlockData[], options?: { index?: number }): BlockNode[];\n /**\n * Atomically split a block: update `currentBlockId` with `currentBlockData`\n * and insert a new `newBlockType` block at `insertIndex`, as ONE undo step.\n * Delegates to core's `splitBlock`. Returns the new node, or null pre-ready /\n * on an unknown id.\n */\n splitBlock(\n currentBlockId: string,\n currentBlockData: Partial<BlockToolData>,\n newBlockType: string,\n newBlockData: BlockToolData,\n insertIndex: number\n ): BlockNode | null;\n /**\n * Insert a single child block under `parentId` at flat `insertIndex`, atomically\n * (block creation AND parent assignment in ONE undo step) — delegates to core's\n * `blocks.insertInsideParent`. This is the atomic nested-child creator: prefer it\n * over `insert()` + `nest()`, which is TWO undo steps. A dangling `parentId` is a\n * no-op returning `null` (mirrors {@link insert}); an unknown child tool returns\n * `null`. `childData` defaults to an empty paragraph. Returns the created\n * {@link BlockNode}, fresh-snapshot volatile — read it now, don't stash it in a\n * dep array. Pre-ready: `null`.\n */\n insertInsideParent(parentId: string, insertIndex: number, childData?: BlockToolData): BlockNode | null;\n /**\n * Replace the WHOLE document with blocks parsed from saved {@link OutputData}\n * (the `save()` shape) — delegates to core's `blocks.render`. Unlike\n * {@link insertOutputData}/{@link insertMarkdown} (which are ADDITIVE), this\n * CLEARS existing content first: a document-LOAD primitive, not an insert. The\n * HTML counterpart is {@link renderFromHTML}. Async. Pre-ready: resolves\n * immediately (no-op).\n */\n render(data: OutputData): Promise<void>;\n /**\n * Remove EVERY block from the document — delegates to core's `blocks.clear`. A\n * document-reset primitive (pairs with {@link render}). Async. Pre-ready:\n * resolves immediately (no-op).\n */\n clear(): Promise<void>;\n /**\n * Whether a Yjs sync (undo/redo) is currently in progress — the React mirror of\n * core's `blocks.isSyncingFromYjs`. A METHOD (not a property) so it reads the\n * LIVE flag at call time even though the api handle is memoized. Use it to skip\n * cleanup that would fight Yjs state during an undo/redo. Pre-ready: `false`.\n */\n isSyncingFromYjs(): boolean;\n}\n\n/** The minimal slice of editor.blocks that the snapshot helpers read. */\nexport interface BlocksReader {\n getBlocksCount(): number;\n getBlockByIndex(index: number): { id: string; name: string; parentId: string | null } | undefined;\n}\n\n/**\n * Enumerate the editor's blocks once into BlockNode records, in flat order,\n * deriving each node's contentIds from the children that name it as parent.\n */\nexport const snapshotNodes = (reader: BlocksReader): BlockNode[] => {\n const count = reader.getBlocksCount();\n const flat = Array.from({ length: count }, (_, i) => reader.getBlockByIndex(i))\n .filter((b): b is { id: string; name: string; parentId: string | null } => b !== undefined)\n .map((b) => ({ id: b.id, type: b.name, parentId: b.parentId }));\n\n const childrenByParent = new Map<string, string[]>();\n\n for (const b of flat) {\n if (b.parentId === null) {\n continue;\n }\n const bucket = childrenByParent.get(b.parentId) ?? [];\n\n bucket.push(b.id);\n childrenByParent.set(b.parentId, bucket);\n }\n\n return flat.map((b) => ({\n id: b.id,\n type: b.type,\n parentId: b.parentId,\n contentIds: childrenByParent.get(b.id) ?? [],\n }));\n};\n\n/** BlocksReader plus id→flat-index lookup. */\nexport interface IndexReader extends BlocksReader {\n getBlockIndex(id: string): number | undefined;\n}\n\n/** Flat indices of a parent's direct children, ascending. Empty if none. */\nconst childFlatIndices = (reader: IndexReader, parentId: string): number[] => {\n const count = reader.getBlocksCount();\n\n return Array.from({ length: count }, (_, i) => i).filter(\n (i) => reader.getBlockByIndex(i)?.parentId === parentId\n );\n};\n\n/** Map of block id -> parentId, in flat order. */\nexport const parentMap = (reader: BlocksReader): Map<string, string | null> => {\n const count = reader.getBlocksCount();\n const entries = Array.from({ length: count }, (_, i) => reader.getBlockByIndex(i))\n .filter((b): b is { id: string; name: string; parentId: string | null } => b !== undefined)\n .map((b): [string, string | null] => [b.id, b.parentId]);\n\n return new Map(entries);\n};\n\n/** True if `id` descends from `ancestorId` via the parentId chain. */\nexport const isDescendantOf = (\n parentOf: Map<string, string | null>,\n id: string,\n ancestorId: string\n): boolean => {\n const parent = parentOf.get(id) ?? null;\n\n if (parent === null) {\n return false;\n }\n\n return parent === ancestorId || isDescendantOf(parentOf, parent, ancestorId);\n};\n\n/**\n * The flat index of the last block in the contiguous subtree rooted at `index`.\n * In flat (DFS) order a block's descendants sit immediately after it, so this\n * walks forward while blocks remain descendants of the block at `index`.\n * Returns `index` itself when the block has no descendants.\n */\nexport const subtreeEndIndex = (reader: BlocksReader, index: number): number => {\n const root = reader.getBlockByIndex(index);\n\n if (root === undefined) {\n return index;\n }\n\n const parentOf = parentMap(reader);\n const count = reader.getBlocksCount();\n // Walk forward from index+1 while blocks remain descendants (DFS contiguity).\n // The subtree ends just before the first non-descendant, or at the last block\n // when every follower is a descendant.\n const followers = Array.from({ length: count - (index + 1) }, (_, k) => index + 1 + k);\n const breakAt = followers.find((i) => {\n const b = reader.getBlockByIndex(i);\n\n return b === undefined || !isDescendantOf(parentOf, b.id, root.id);\n });\n\n return breakAt === undefined ? count - 1 : breakAt - 1;\n};\n\n/**\n * The flat index at which a new block should be inserted.\n *\n * `replace` flips the meaning of a before/after `position`: under replace the\n * ref IS the block being overwritten (a \"turn into\"), not a sibling anchor, so\n * it resolves to the ref's OWN flat slot regardless of which parent it lives in\n * — bypassing the sibling-relative parent guard that would otherwise redirect a\n * nested target to the requested parent's end and replace the wrong block.\n */\nexport const resolveInsertIndex = (\n reader: IndexReader,\n parentId: string | null,\n position: InsertPosition,\n replace = false\n): number => {\n if (typeof position === 'object') {\n const ref = 'before' in position ? position.before : position.after;\n const refIndex = reader.getBlockIndex(ref);\n\n if (replace && refIndex !== undefined) {\n return refIndex;\n }\n\n const refParent =\n refIndex === undefined ? undefined : reader.getBlockByIndex(refIndex)?.parentId ?? null;\n\n // before/after is sibling-relative: the ref must be a child of the requested\n // parent. When the ref is missing or lives in a DIFFERENT parent, the\n // parentId constraint wins — fall back to appending at the end of the\n // requested parent rather than splicing into an unrelated subtree (the\n // cross-parent mis-place) or silently landing at the document end.\n if (refIndex === undefined || refParent !== parentId) {\n return resolveInsertIndex(reader, parentId, 'end');\n }\n\n // 'after' must clear the ref's entire subtree, not just the ref node, or the\n // new block splits the ref's descendants in flat (DFS) order.\n return 'before' in position ? refIndex : subtreeEndIndex(reader, refIndex) + 1;\n }\n\n if (parentId === null) {\n return position === 'start' ? 0 : reader.getBlocksCount();\n }\n\n const parentIndex = reader.getBlockIndex(parentId);\n\n if (parentIndex === undefined) {\n return reader.getBlocksCount();\n }\n\n if (position === 'start') {\n const childIndices = childFlatIndices(reader, parentId);\n\n return childIndices.length === 0 ? parentIndex + 1 : childIndices[0];\n }\n\n // 'end': insert after the parent's last descendant.\n return subtreeEndIndex(reader, parentIndex) + 1;\n};\n\n/** The flat toIndex for editor.blocks.move. */\nexport const resolveMoveIndex = (reader: IndexReader, target: MoveTarget): number => {\n if ('toIndex' in target) {\n // Blok's Blocks.move() silently no-ops on an out-of-range index, so clamp\n // an explicit toIndex into [0, count-1] rather than dropping the move.\n const lastIndex = Math.max(0, reader.getBlocksCount() - 1);\n\n return Math.min(Math.max(target.toIndex, 0), lastIndex);\n }\n\n const ref = 'before' in target ? target.before : target.after;\n const refIndex = reader.getBlockIndex(ref);\n\n if (refIndex === undefined) {\n return reader.getBlocksCount();\n }\n\n // 'after' must clear the ref's entire subtree (see resolveInsertIndex), or the\n // moved block lands among the ref's descendants instead of past them.\n return 'before' in target ? refIndex : subtreeEndIndex(reader, refIndex) + 1;\n};\n","import type { Blok, BlockToolData, BlockTuneData, OutputBlockData, OutputData, MarkdownImportConfig } from '@bloklabs/core';\n// src/components/utils/blocks-api.ts\nimport { ToolNotFoundError } from '../errors/tool-not-found';\nimport { HOST_PRESERVED_DATA } from './host-preserved-data';\n\nimport { flattenTree } from '../../shared/flatten-tree';\nimport {\n snapshotNodes,\n resolveInsertIndex,\n resolveMoveIndex,\n parentMap,\n type BlockNode,\n type CaretTarget,\n type IndexReader,\n type InsertPosition,\n type InsertSpec,\n type MoveTarget,\n type TreeInsertSpec,\n type UseBlocksApi,\n} from './blocks-tree';\n\n/** Adapt the live editor to the IndexReader the snapshot helpers expect. */\nexport const readerFor = (editor: Blok): IndexReader => {\n const blocks = editor.blocks;\n\n return {\n getBlocksCount: () => blocks.getBlocksCount(),\n getBlockByIndex: (i: number) => {\n const b = blocks.getBlockByIndex(i);\n\n return b === undefined ? undefined : { id: b.id, name: b.name, parentId: b.parentId };\n },\n getBlockIndex: (id: string) => blocks.getBlockIndex(id),\n };\n};\n\n/**\n * Stable API returned while the editor is null (before the adapter resolves).\n * Every read returns empty/null and every MUTATOR is a no-op — EXCEPT\n * `transact`/`transactWithoutCapture`, which still invoke their callback so a\n * consumer wrapping conditional work in `transact` still runs that work even\n * pre-ready.\n */\nexport const EMPTY_API: UseBlocksApi = {\n getById: () => null,\n getChildren: () => [],\n insert: () => null,\n insertMany: () => [],\n insertTree: () => null,\n insertMarkdown: async () => [],\n exportMarkdown: async () => '',\n move: () => undefined,\n nest: () => undefined,\n unnest: () => undefined,\n remove: () => undefined,\n update: () => undefined,\n convert: () => undefined,\n // Not a no-op: still runs the callback (see EMPTY_API doc above).\n transact: (fn: () => void) => fn(),\n // Like transact, still runs the callback even pre-ready.\n transactWithoutCapture: (fn: () => void) => fn(),\n getBlocksCount: () => 0,\n getCurrentBlockIndex: () => -1,\n getBlockByIndex: () => null,\n getBlockByElement: () => null,\n getBlockData: () => null,\n getBlockIndex: () => null,\n composeBlockData: async () => ({}),\n renderFromHTML: async () => undefined,\n insertOutputData: () => [],\n splitBlock: () => null,\n insertInsideParent: () => null,\n render: async () => undefined,\n clear: async () => undefined,\n isSyncingFromYjs: () => false,\n};\n\n/**\n * Read the changed block's id out of a `block changed` payload, tolerating any\n * shape that is not core's `{ event: { detail: { target } } }`.\n * @param payload - whatever the dispatcher handed the listener\n * @returns the target block id, or null when the payload does not carry one\n */\nconst changedBlockId = (payload: unknown): string | null => {\n const detail = (payload as { event?: { detail?: { target?: { id?: unknown } } } } | undefined)\n ?.event?.detail?.target?.id;\n\n return typeof detail === 'string' ? detail : null;\n};\n\n/**\n * Does a `block changed` event touch the subtree rooted at `withinId`?\n *\n * The reactivity filter behind `useBlocks(editor, { within })` in all three\n * adapters. Without it every consumer of `useBlocks` re-renders on every change\n * anywhere in the document — so a container block that only renders its own\n * children still re-rendered on each keystroke in an unrelated block, and a page\n * of N such containers turned one keystroke into N re-renders.\n *\n * INDETERMINATE READS AS \"TOUCHED\". The walk resolves ancestry through the LIVE\n * tree, and a removal commonly emits after the block is already gone, so its\n * parent chain cannot be read. Answering `false` there would leave a container\n * rendering a child that no longer exists; answering `true` costs one extra\n * render pass. Same for a payload with no readable target.\n *\n * Ancestry is walked UPWARD one `getById` at a time rather than snapshotted with\n * `parentMap`: this runs on every emission — i.e. on every keystroke — so it must\n * cost O(depth), not O(document).\n * @param editor - the live Blok instance\n * @param payload - the `block changed` payload\n * @param withinId - id of the block whose subtree is the scope\n * @returns true when the change is inside the scope (or cannot be placed)\n */\nexport const changeTouchesSubtree = (\n editor: Blok,\n payload: unknown,\n withinId: string\n): boolean => {\n const targetId = changedBlockId(payload);\n\n if (targetId === null) {\n return true;\n }\n\n /** Ids already visited on this walk — one Set for the whole climb. */\n const seen = new Set<string>();\n\n /**\n * Walk one link up the parentId chain.\n * @param id - the block to test, or null once the root is passed\n * @returns true when `withinId` is `id` or one of its ancestors\n */\n const climbs = (id: string | null): boolean => {\n if (id === null) {\n return false;\n }\n\n if (id === withinId) {\n return true;\n }\n\n // A parentId cycle is a corrupt tree, not a scope hit — bail rather than spin.\n if (seen.has(id)) {\n return false;\n }\n\n seen.add(id);\n\n const node = editor.blocks.getById(id);\n\n // The target (or one of its ancestors) is no longer in the tree.\n if (node === null || node === undefined) {\n return true;\n }\n\n return climbs(node.parentId);\n };\n\n return climbs(targetId);\n};\n\n/**\n * Build the framework-agnostic, id/parentId-relative block-tree API over a LIVE\n * editor. Mutators route through the editor-level `blocks` API (core's\n * chokepoints), so undo/redo and Yjs sync are inherited rather than\n * re-implemented; readers enumerate the live tree on every call.\n *\n * This is the shared engine behind both the React (`useSyncExternalStore`) and\n * Vue (`shallowRef` version) `useBlocks` wrappers — one implementation so the\n * two adapters cannot drift. Each adapter supplies the `onRead` seam:\n *\n * - React leaves it the default no-op: `useSyncExternalStore` re-renders the\n * whole component on `block changed`, and the reads run live during that\n * render, so no per-call dependency tracking is needed.\n * - Vue passes `() => { void version.value }` so a read inside a `computed` /\n * template touches the reactive version ref and re-runs on every structural\n * mutation.\n *\n * `onRead` is invoked at the top of every read method; mutators never call it.\n * The editor MUST be the raw (non-proxied) instance — adapters `toRaw`-unwrap\n * before calling, so a Vue reactive proxy never reaches core (Risk R0).\n *\n * @param editor - the live Blok instance (never null; callers gate on EMPTY_API)\n * @param onRead - reactivity seam called at the start of each read (default no-op)\n */\nexport const createBlocksApiForEditor = (\n editor: Blok,\n onRead: () => void = () => undefined\n): UseBlocksApi => {\n const reader = readerFor(editor);\n\n const getById = (id: string): BlockNode | null => {\n onRead();\n const nodes = snapshotNodes(reader);\n\n return nodes.find((n) => n.id === id) ?? null;\n };\n\n const getChildren = (parentId: string | null): BlockNode[] => {\n onRead();\n\n return snapshotNodes(reader).filter((n) => n.parentId === parentId);\n };\n\n const transact = (fn: () => void): void => {\n if (editor.blocks.transact !== undefined) {\n editor.blocks.transact(fn);\n } else {\n fn();\n }\n };\n\n /** Flat list of id + all transitive descendants, via the parentId graph. */\n const collectSubtreeIds = (rootId: string): string[] => {\n const nodes = snapshotNodes(reader);\n const childrenOf = new Map<string, string[]>();\n\n for (const n of nodes) {\n if (n.parentId === null) {\n continue;\n }\n const bucket = childrenOf.get(n.parentId) ?? [];\n\n bucket.push(n.id);\n childrenOf.set(n.parentId, bucket);\n }\n\n const out: string[] = [];\n const visited = new Set<string>();\n const stack: string[] = [rootId];\n\n // A parentId cycle (possible from a concurrent remote Yjs reparent) would\n // make this DFS spin forever — track visited ids and skip re-entry so each\n // block is emitted at most once and the traversal always terminates.\n while (stack.length > 0) {\n const id = stack.pop() as string;\n\n if (visited.has(id)) {\n continue;\n }\n visited.add(id);\n out.push(id);\n const kids = childrenOf.get(id);\n\n if (kids !== undefined) {\n stack.push(...kids);\n }\n }\n\n return out;\n };\n\n /**\n * Run a core placement call, turning a refused place into a no-op. Core's\n * `insertAt`/`moveTo` throw a `BlockPlacementError` for a missing block, a\n * cycle, or a parent that refuses the block; the hook's contract is a\n * silent no-op there. Matched by name, not `instanceof`, so a copy of the\n * class from another bundle still matches.\n * @param run - the core call\n * @returns its result, or null when core refused the place\n */\n const placeOrSkip = <T>(run: () => T): T | null => {\n try {\n return run();\n } catch (error) {\n if (error instanceof Error && error.name === 'BlockPlacementError') {\n return null;\n }\n throw error;\n }\n };\n\n /** Whether `id` is a direct child of a `column`. */\n const isColumnChild = (id: string): boolean => {\n const parent = getById(id)?.parentId ?? null;\n\n return parent !== null && getById(parent)?.type === 'column';\n };\n\n /**\n * Nest `id` (and its whole subtree) under `parentId` as its last child, as\n * one undo step. No-op when either id is unknown, when `parentId` is `id`\n * itself or one of its descendants, or when the parent refuses the block.\n * Nesting out of a `column` or directly into one is a no-op too: column\n * membership belongs to the drag UI. Returns void.\n */\n const nest = (id: string, parentId: string): void => {\n if (isColumnChild(id) || getById(parentId)?.type === 'column') {\n return;\n }\n\n placeOrSkip(() => editor.blocks.moveTo(id, { parentId, position: 'end' }));\n };\n\n /**\n * Promote `id` (and its subtree) to root, right after its top-level\n * ancestor's subtree, as one undo step. No-op when the id is unknown or\n * already at root, and for a `column` member (column membership changes go\n * through the drag UI). Returns void.\n */\n const unnest = (id: string): void => {\n const parentOf = parentMap(reader);\n const topLevelAncestor = (cursor: string, seen: Set<string>): string => {\n const parent = parentOf.get(cursor) ?? null;\n\n return parent === null || seen.has(parent) ? cursor : topLevelAncestor(parent, seen.add(cursor));\n };\n const parentId = parentOf.get(id) ?? null;\n\n if (parentId === null || isColumnChild(id)) {\n return;\n }\n\n const anchor = topLevelAncestor(parentId, new Set<string>([id]));\n\n placeOrSkip(() => editor.blocks.moveTo(id, { parentId: null, position: { after: anchor } }));\n };\n\n const remove = (id: string): void => {\n if (editor.blocks.getBlockIndex(id) === undefined) {\n return;\n }\n\n // Remove the block AND its descendants. Blok's single-block delete promotes\n // a (non-columns) container's children to root, which would orphan the\n // nested structure the caller meant to discard. Delete deepest-first (by\n // descending flat index) so a parent is childless by the time it's deleted\n // (no promotion). One undo step.\n //\n // Re-resolve each member's index by id AT DELETE TIME rather than reusing a\n // pre-captured snapshot: a core delete can cascade (deleting a column's last\n // child auto-removes the empty column) or shift indices, so a stale index\n // could target the wrong — or an already-gone — block.\n const orderedIds = collectSubtreeIds(id)\n .map((subId) => ({ subId, index: editor.blocks.getBlockIndex(subId) }))\n .filter((m): m is { subId: string; index: number } => m.index !== undefined)\n .sort((a, b) => b.index - a.index)\n .map((m) => m.subId);\n\n transact(() => {\n for (const subId of orderedIds) {\n const index = editor.blocks.getBlockIndex(subId);\n\n // Already removed by a cascading delete of one of its descendants.\n if (index === undefined) {\n continue;\n }\n void editor.blocks.delete(index, false);\n }\n });\n };\n\n /**\n * Move `id` to a sibling slot or a flat index. No-op when `id` is unknown.\n *\n * `before`/`after` make the block a SIBLING of the ref: it takes the ref's\n * parent, and `after` lands past the ref's whole subtree. The block carries\n * its whole subtree, as one undo step. A ref that is missing, the block\n * itself, or inside its subtree is a no-op, as is a move that core refuses\n * (column membership, a parent that does not take the block).\n *\n * `{ toIndex }` is an absolute flat index (clamped into range); the block\n * takes the parent of the slot it lands in. It is a no-op for a block that\n * HAS descendants: a multi-block subtree cannot land on one index — use\n * `{ before|after }` for that. Returns void.\n */\n const move = (id: string, target: MoveTarget): void => {\n if (!('toIndex' in target)) {\n placeOrSkip(() => editor.blocks.moveTo(id, { position: target }));\n\n return;\n }\n\n // Silent existence probe (NOT getBlockIndex, which warns on unknown ids).\n if (getById(id) === null || collectSubtreeIds(id).length > 1) {\n return;\n }\n\n const fromIndex = editor.blocks.getBlockIndex(id);\n\n if (fromIndex !== undefined) {\n editor.blocks.move(resolveMoveIndex(reader, target), fromIndex);\n }\n };\n\n /**\n * Perform one insert (create + intended-parent assertion) WITHOUT opening a\n * transaction — the caller owns the undo grouping. `insert` wraps a single\n * call in its own transact; `insertMany` shares ONE transact across the whole\n * batch so the bulk insert is a single undo step. Returns the created node,\n * or null when nothing was inserted (idempotent hit returns the existing\n * node; a guard failure returns null).\n */\n const insertWithinTransaction = (spec: InsertSpec): { node: BlockNode | null; created: boolean } => {\n const parentId = spec.parentId ?? null;\n const position = spec.position ?? 'end';\n const data = spec.data ?? {};\n // Programmatic insert must not steal the caret unless explicitly asked.\n const needToFocus = spec.focus ?? false;\n const replace = spec.replace ?? false;\n\n // Every pre-insert guard (id-exists, dangling-parent, missing-ref) and the\n // replace-parent lookup used to call `getById`, which re-enumerates the\n // WHOLE tree each time — O(probes·n) per spec, O(k·probes·n) per batch.\n // The tree can't change until `editor.blocks.insertAt` runs below, so take\n // ONE snapshot here and resolve every pre-insert probe against it.\n const preById = new Map(snapshotNodes(reader).map((n) => [n.id, n]));\n const probe = (id: string): BlockNode | null => preById.get(id) ?? null;\n\n // Idempotent insert-if-absent: a stable explicit id that already exists\n // returns the existing node without inserting a duplicate, so a re-running\n // effect is safe. Probe via the silent snapshot getById, NOT\n // editor.blocks.getBlockIndex — the latter logs a `warn` for any unknown\n // id, which would spam the console on this (expected-absent) happy path.\n //\n // Skipped under `replace`: a replace is an explicit overwrite, not an\n // insert, so an existing id must not short-circuit it (the two would\n // otherwise silently conflict and replace nothing).\n if (spec.id !== undefined && !replace) {\n const existing = probe(spec.id);\n\n if (existing !== null) {\n // Insert-if-absent hit: the block already existed, nothing was created.\n // insert() still returns the existing node (documented), but insertMany\n // must EXCLUDE it from its created[] result — hence created: false.\n return { node: existing, created: false };\n }\n }\n\n // A dangling parentId would make core throw (dev) or silently misplace the\n // block at the document end (prod). Honor the null contract instead. Probe\n // via the silent snapshot getById, NOT editor.blocks.getBlockIndex, which\n // logs a `warn` for any unknown id and would spam the console on this\n // expected-absent no-op path. Skipped under replace: a replace ignores\n // parentId entirely (the overwritten block's own parent governs), so a\n // stale parentId must not abort the overwrite.\n if (!replace && parentId !== null && probe(parentId) === null) {\n return { node: null, created: false };\n }\n\n // A replace targets the before/after ref block ITSELF (the \"turn into\"\n // block being overwritten), not a sibling anchor. It therefore REQUIRES an\n // object position naming that ref:\n // - with position 'start'/'end' (or omitted) there is no target ref, so\n // a replace has nothing to overwrite — return null rather than silently\n // overwriting whatever block happens to sit at the resolved slot;\n // - with an object position whose ref doesn't exist there is likewise\n // nothing to overwrite — return null.\n // Validation is skipped for a plain insert (above), so this is the only\n // guard that protects the replace path.\n if (replace) {\n if (typeof position !== 'object') {\n return { node: null, created: false };\n }\n\n const replaceTargetRef = 'before' in position ? position.before : position.after;\n\n if (probe(replaceTargetRef) === null) {\n return { node: null, created: false };\n }\n }\n\n // A plain insert with an object position naming a ref that does NOT exist\n // must be a no-op (return null), NOT the append-at-end fallback below for a\n // ref under another parent. (Skipped under replace: the block above already\n // validated the replace ref.)\n if (!replace && typeof position === 'object') {\n const positionTargetRef = 'before' in position ? position.before : position.after;\n\n if (probe(positionTargetRef) === null) {\n return { node: null, created: false };\n }\n }\n\n const ref = ((): string | null => {\n if (typeof position !== 'object') {\n return null;\n }\n\n return 'before' in position ? position.before : position.after;\n })();\n const options = replace && ref !== null\n ? { replace: ref, id: spec.id, tunes: spec.tunes, focus: needToFocus }\n : {\n parentId,\n // before/after is relative to a child of `parentId`. A ref under\n // another parent falls back to the end of `parentId` (documented).\n position: ref !== null && probe(ref)?.parentId !== parentId ? 'end' : position,\n id: spec.id,\n tunes: spec.tunes,\n focus: needToFocus,\n };\n\n const created = ((): { id: string } | null => {\n try {\n return placeOrSkip(() => editor.blocks.insertAt(spec.type, data, options));\n } catch (error) {\n // An unknown tool is an expected outcome (null); anything else is a bug.\n if (error instanceof ToolNotFoundError) {\n return null;\n }\n throw error;\n }\n })();\n\n if (created === null) {\n return { node: null, created: false };\n }\n\n const node = snapshotNodes(reader).find((n) => n.id === created.id) ?? null;\n\n // Position the caret inside the freshly-created block when the caller asked\n // for a specific spot (beyond the boolean `focus`). Applied only on a real\n // creation — an insert-if-absent hit returned earlier, so it never reaches\n // here. setToBlock takes the block id directly.\n if (spec.caret !== undefined) {\n editor.caret.setToBlock(created.id, spec.caret.position ?? 'default', spec.caret.offset ?? 0);\n }\n\n return { node, created: true };\n };\n\n /**\n * Insert one block. Returns the created {@link BlockNode}, or null when the\n * insert is rejected — an unknown tool type (core \"…not found\"), a dangling\n * `parentId`, or a `replace` whose target ref doesn't exist. An explicit\n * `id` that already exists is insert-if-absent: the existing node is returned\n * and nothing is created (skipped under `replace`, which is an explicit\n * overwrite). Validation runs BEFORE the slot is resolved; a `replace`\n * preserves the overwritten block's parent. Always one atomic undo step.\n *\n * The returned node is a fresh-snapshot view (its `contentIds` are derived\n * per call) — read it immediately; do NOT place it in a `useMemo`/`useEffect`\n * dependency array expecting per-mutation identity.\n */\n const insert = (spec: InsertSpec = {}): BlockNode | null => {\n // Mutable property on a const holder (no `let`): the node captured from\n // inside the transact closure for the post-transact return.\n const result: { node: BlockNode | null } = { node: null };\n\n // Always atomic: a single undo step removes the new block (and, for a\n // parented insert, its reparent) — and gives the insert its own boundary\n // instead of merging into adjacent typing history.\n transact(() => {\n // insert() returns the resolved node — including an insert-if-absent hit's\n // existing node (documented) — so it reads only `.node`, not `.created`.\n result.node = insertWithinTransaction(spec).node;\n });\n\n return result.node;\n };\n\n const insertMany = (specs: InsertSpec[]): BlockNode[] => {\n // An empty batch opens no transaction (no spurious undo boundary).\n if (specs.length === 0) {\n return [];\n }\n\n const created: BlockNode[] = [];\n\n // ONE transact for the whole batch → a single atomic undo step. Each spec\n // still runs the full single-insert path (parent assertion, positioning).\n // Per the documented contract, the result holds ONLY successfully-created\n // nodes: specs that fail to insert (null node) AND insert-if-absent hits\n // (existing block, created: false) are both dropped.\n transact(() => {\n for (const spec of specs) {\n const result = insertWithinTransaction(spec);\n\n if (result.created && result.node !== null) {\n created.push(result.node);\n }\n }\n });\n\n return created;\n };\n\n /**\n * Insert a pre-built nested subtree as ONE atomic operation. See the\n * {@link UseBlocksApi.insertTree} contract. Flattens the spec to a DFS\n * pre-order `OutputBlockData[]` — wiring every node's `parent`/`content`\n * links from ids generated up front — then delegates to core's tree-aware\n * `blocks.insertMany` inside a single transact.\n */\n const insertTree = (spec: TreeInsertSpec): BlockNode | null => {\n const parentId = spec.parentId ?? null;\n const position = spec.position ?? 'end';\n\n // Dangling root parentId: mirror `insert`'s guard via the silent snapshot\n // getById (NOT getBlockIndex, which warns on unknown ids). Reject so the\n // subtree isn't silently dumped at the document end.\n if (parentId !== null && getById(parentId) === null) {\n return null;\n }\n\n // Dangling relative position ref: an object { before|after } naming a block\n // that does not exist must be a no-op, NOT a silent append at the document\n // end (resolveInsertIndex's unresolved-ref fallback). Mirror insert()'s\n // missing-ref guard and reject before flattening anything.\n if (typeof position === 'object') {\n const positionTargetRef = 'before' in position ? position.before : position.after;\n\n if (getById(positionTargetRef) === null) {\n return null;\n }\n }\n\n // Flatten the nested spec to a DFS pre-order array with wired\n // `parent`/`content` links — the same transform used to seed nested data,\n // shared as the pure `flattenTree` helper. `parentId` becomes the root's\n // `parent`. flattenTree throws on an id reused WITHIN the spec (a duplicate\n // would corrupt every id-keyed lookup); a tree insert always creates fresh\n // blocks (NOT insert-if-absent), so that is rejected up front — null,\n // mirroring insert's null contract.\n const flat = (() => {\n try {\n return flattenTree(spec, { parentId: parentId ?? undefined });\n } catch {\n return null;\n }\n })();\n\n if (flat === null) {\n return null;\n }\n\n // External collision: an explicit id already present in the live tree would\n // also create a duplicate-id block. Snapshot the existing ids once and\n // reject if any flat node reuses one. Generated ids never collide.\n const existingIds = new Set(snapshotNodes(reader).map((n) => n.id));\n\n if (flat.some((node) => existingIds.has(node.id))) {\n return null;\n }\n\n const rootId = flat[0].id;\n\n // flattenTree omits `content` on leaves (clean seed-data shape). insertMany\n // wants every node to carry an explicit child-id array — a leaf's\n // `contentIds: []` states \"no children\" rather than leaving it undefined —\n // so stamp the empty array back on before handing the batch to core.\n for (const node of flat) {\n if (node.content === undefined) {\n node.content = [];\n }\n }\n\n const flatIndex = resolveInsertIndex(reader, parentId, position);\n\n // ONE transact for the whole subtree → a single atomic undo step. Core's\n // insertMany composes EVERY node before inserting any, so an unknown tool\n // type throws a typed ToolNotFoundError with nothing inserted. Honor the\n // same null-on-unknown-tool contract as insert/insertMany rather than\n // surfacing the throw to the caller; re-throw any other (genuine-bug)\n // error. Keyed on the error TYPE, not a 'not found' substring.\n try {\n transact(() => {\n editor.blocks.insertMany(flat, flatIndex);\n });\n } catch (error) {\n if (error instanceof ToolNotFoundError) {\n return null;\n }\n throw error;\n }\n\n return getById(rootId);\n };\n\n /**\n * Convert markdown to blocks and insert them ADDITIVELY — see the\n * {@link UseBlocksApi.insertMarkdown} doc for the full contract. Async\n * because the converter is lazy-loaded; the insert itself is one atomic\n * undo step. parentId nesting is supported: top-level converted blocks are\n * reparented under parentId, internally-nested ones keep their parent.\n */\n const insertMarkdown = async (\n markdown: string,\n options?: { parentId?: string | null; position?: InsertPosition; config?: MarkdownImportConfig }\n ): Promise<BlockNode[]> => {\n const parentId = options?.parentId ?? null;\n const position = options?.position ?? 'end';\n\n // A dangling parentId is a no-op (no insert), matching `insert`/`insertMany`.\n if (parentId !== null && getById(parentId) === null) {\n return [];\n }\n\n // A dangling relative position ref is likewise a no-op (no insert), NOT a\n // silent append at the document end — mirror insert()/insertTree's guard.\n if (typeof position === 'object') {\n const positionTargetRef = 'before' in position ? position.before : position.after;\n\n if (getById(positionTargetRef) === null) {\n return [];\n }\n }\n\n // Lazy-load the converter (dynamic import mirrors core's markdown lazy\n // loading and keeps the parser out of the main bundle) and run it,\n // forwarding the optional MarkdownImportConfig so custom-tool consumers can\n // map markdown nodes into their tools (gfm toggle, toolMap, extensions).\n // Both awaits can fail — a chunk-load error or a malformed-markdown throw;\n // swallow them and return [] so a converter failure is a graceful no-op\n // (matching update/convert) rather than an unhandled promise rejection in\n // the caller. This await resolves BEFORE the synchronous transact.\n // Mutable property on a const holder (no `let`): captured from the try.\n const conversion: { blocks: OutputBlockData[] } = { blocks: [] };\n\n try {\n const { markdownToBlocks } = await import('@bloklabs/core/markdown');\n\n // HTML text: what insertMany hands tools, and what the editor's own save gates expect.\n // Typed inline: the Angular build maps markdown/types to @bloklabs/core, which lacks InternalMarkdownImportConfig.\n const config: MarkdownImportConfig & { htmlText: boolean } = { ...options?.config, htmlText: true };\n\n conversion.blocks = await markdownToBlocks(markdown, config);\n } catch (error) {\n // Graceful no-op: a converter failure (chunk-load or parse error) returns\n // [] rather than surfacing an unhandled rejection to the caller. But\n // surface it to the console so a genuine converter bug is DISTINGUISHABLE\n // from empty markdown (which returns [] via the blocks.length === 0 path\n // below, without ever reaching this catch) instead of being swallowed\n // silently and losing all diagnostics.\n console.warn('useBlocks.insertMarkdown: markdown conversion failed', error);\n\n return [];\n }\n\n const blocks = conversion.blocks;\n\n // Empty / whitespace-only markdown opens no transaction (no undo boundary).\n if (blocks.length === 0) {\n return [];\n }\n\n // Re-validate the parent AFTER the await: the pre-await existence check can\n // go stale if the parent was removed while the converter was in flight.\n // Stamping a now-dangling parent would orphan the blocks instead of the\n // promised [] no-op, so re-check and bail out here.\n if (parentId !== null && getById(parentId) === null) {\n return [];\n }\n\n // Re-validate the relative position ref after the await too: the target\n // could have been removed while the converter was in flight, in which case\n // inserting at the stale slot would surprise the caller. No-op instead.\n if (typeof position === 'object') {\n const positionTargetRef = 'before' in position ? position.before : position.after;\n\n if (getById(positionTargetRef) === null) {\n return [];\n }\n }\n\n // Nest under the parent by stamping `parent` on each TOP-LEVEL block (one\n // the converter left un-parented). Blocks the markdown nested internally\n // (their `parent` already points at a sibling in this batch) are untouched,\n // so the import's own structure is preserved.\n const seeded: OutputBlockData[] =\n parentId === null\n ? blocks\n : blocks.map((block) =>\n block.parent === undefined || block.parent === null\n ? { ...block, parent: parentId }\n : block\n );\n\n const flatIndex = resolveInsertIndex(reader, parentId, position);\n\n // Mutable property on a const holder (no `let`): captured from inside the\n // transact closure. insertMany returns BlockAPI[] (each has `.id`) — the\n // reliable record of what was created, since the converter's ids may not\n // survive composition. ONE transact → a single atomic undo step.\n const result: { created: Array<{ id: string }> } = { created: [] };\n\n // The insert lives OUTSIDE the conversion try/catch, so an unknown mapped\n // tool (core throws a typed ToolNotFoundError) would otherwise surface as an\n // unhandled promise rejection. Honor the same null-on-unknown-tool contract\n // as insertTree — return [] — and re-throw any other (genuine-bug) error.\n // Keyed on the error TYPE, not a 'not found' substring.\n try {\n transact(() => {\n result.created = editor.blocks.insertMany(seeded, flatIndex);\n });\n } catch (error) {\n if (error instanceof ToolNotFoundError) {\n return [];\n }\n throw error;\n }\n\n return result.created\n .map((block) => getById(block.id))\n .filter((node): node is BlockNode => node !== null);\n };\n\n const update = (\n id: string,\n data?: BlockToolData,\n tunes?: { [name: string]: BlockTuneData }\n ): void => {\n // Silent existence probe (NOT getBlockIndex, which warns on unknown ids).\n if (getById(id) === null) {\n return;\n }\n\n // Core update is async and forms its own undo/Yjs step, so it is NOT\n // wrapped in transact (that would close the group before the write lands).\n // Swallow any rejection so it can't surface as an unhandled rejection.\n void Promise.resolve(editor.blocks.update(id, data, tunes)).catch(() => undefined);\n };\n\n const convert = (\n id: string,\n newType: string,\n dataOverrides?: BlockToolData,\n options?: { caret?: CaretTarget }\n ): void => {\n if (getById(id) === null) {\n return;\n }\n\n // Core convert is async and rejects when a tool lacks a conversionConfig.\n // Like update, it owns its own history step (no transact). Position the\n // caret only AFTER a successful convert (matching the in-editor keyboard\n // turn-into, which preserves the caret) when the caller asked for it.\n // Swallow the rejection so a non-convertible block is a graceful no-op —\n // and on rejection the caret is left untouched.\n void Promise.resolve(editor.blocks.convert(id, newType, dataOverrides))\n .then((converted) => {\n if (options?.caret !== undefined) {\n // Core convert routes through replace(), which regenerates the block\n // id — the resolved BlockAPI carries the NEW id. Target it (falling\n // back to the original only if a faithless path resolves nothing) so\n // the caret lands in the converted block instead of a stale id.\n const targetId = converted?.id ?? id;\n\n editor.caret.setToBlock(\n targetId,\n options.caret.position ?? 'default',\n options.caret.offset ?? 0\n );\n }\n })\n .catch(() => undefined);\n };\n\n const transactWithoutCapture = (fn: () => void, options?: { derivedFrom?: string; from?: readonly string[] }): void => {\n if (editor.blocks.transactWithoutCapture !== undefined) {\n editor.blocks.transactWithoutCapture(fn, options);\n } else {\n fn();\n }\n };\n\n const getBlocksCount = (): number => {\n onRead();\n\n return editor.blocks.getBlocksCount();\n };\n\n const getCurrentBlockIndex = (): number => {\n onRead();\n\n return editor.blocks.getCurrentBlockIndex();\n };\n\n const getBlockByIndex = (index: number): BlockNode | null => {\n onRead();\n const block = editor.blocks.getBlockByIndex(index);\n\n return block === undefined ? null : getById(block.id);\n };\n\n const getBlockByElement = (element: HTMLElement): BlockNode | null => {\n onRead();\n const block = editor.blocks.getBlockByElement(element);\n\n return block === undefined ? null : getById(block.id);\n };\n\n const composeBlockData = (toolName: string): Promise<BlockToolData> =>\n editor.blocks.composeBlockData(toolName);\n\n const getBlockData = (\n id: string\n ): { data: BlockToolData; tunes: { [name: string]: BlockTuneData } } | null => {\n // Silent existence probe via the snapshot getById (NOT editor.blocks.getById,\n // which logs a `warn` for an unknown id) so a miss is a quiet null, matching\n // getBlockIndex and the other id-taking readers.\n if (getById(id) === null) {\n return null;\n }\n\n const block = editor.blocks.getById(id);\n\n if (block === null) {\n return null;\n }\n\n // preservedData/preservedTunes are core's SYNCHRONOUS last-extracted view —\n // the same snapshot clipboard ops read. Returning it (rather than the async\n // save()) keeps this reader synchronous so a block can be read and re-inserted\n // (duplicated) inside one render/handler without the ref escape hatch.\n const hostData: unknown = Reflect.get(block, HOST_PRESERVED_DATA);\n\n // An older core has no hidden reader: its data is HTML anyway.\n const data = typeof hostData === 'function' ? (hostData as () => BlockToolData)() : block.preservedData;\n\n return { data, tunes: block.preservedTunes };\n };\n\n const getBlockIndex = (id: string): number | null => {\n if (getById(id) === null) {\n // Silent existence probe (NOT editor.blocks.getBlockIndex, which warns on\n // unknown ids) so a miss is a quiet null, matching every other reader.\n return null;\n }\n\n return editor.blocks.getBlockIndex(id) ?? null;\n };\n\n const renderFromHTML = (html: string): Promise<void> => editor.blocks.renderFromHTML(html);\n\n const splitBlock = (\n currentBlockId: string,\n currentBlockData: Partial<BlockToolData>,\n newBlockType: string,\n newBlockData: BlockToolData,\n insertIndex: number\n ): BlockNode | null => {\n // Silent no-op for an unknown current block, matching every other id-taking\n // mutator. Probe via the snapshot getById (NOT getBlockIndex, which warns).\n if (getById(currentBlockId) === null) {\n return null;\n }\n\n // A negative insertIndex is malformed — core would forward it to a splice\n // (which counts from the array end) and silently split at the wrong slot.\n // Honor the silent-no-op convention instead (consistent with\n // insertOutputData's negative-index guard): return null without touching core.\n if (insertIndex < 0) {\n return null;\n }\n\n // An unknown newBlockType makes core's compose path throw a typed\n // ToolNotFoundError — honor the null contract (mirroring insert/insertTree);\n // re-throw any other (genuine-bug) error. Keyed on the error TYPE.\n const created = ((): { id: string } | null | undefined => {\n try {\n return editor.blocks.splitBlock(\n currentBlockId,\n currentBlockData,\n newBlockType,\n newBlockData,\n insertIndex\n );\n } catch (error) {\n if (error instanceof ToolNotFoundError) {\n return null;\n }\n throw error;\n }\n })();\n\n return created === undefined || created === null ? null : getById(created.id);\n };\n\n const insertOutputData = (\n blocks: OutputBlockData[],\n options?: { index?: number }\n ): BlockNode[] => {\n // An empty batch opens no transaction (no spurious undo boundary).\n if (blocks.length === 0) {\n return [];\n }\n\n // A negative index is malformed — core throws a bare validation Error. Honor\n // the silent-no-op convention instead: return [] without inserting (no\n // transaction, no surprise end-append), consistent with the rest of the API.\n if (options?.index !== undefined && options.index < 0) {\n return [];\n }\n\n // ONE transact for the whole batch → a single atomic undo step. Delegates\n // to core's raw insertMany, which honors each block's parent/content links.\n // Honor the same null/[]-on-unknown-tool contract as insertTree (core throws\n // a typed ToolNotFoundError); re-throw any other (genuine-bug) error.\n const result: { created: Array<{ id: string }> } = { created: [] };\n\n try {\n transact(() => {\n result.created =\n options?.index !== undefined\n ? editor.blocks.insertMany(blocks, options.index)\n : editor.blocks.insertMany(blocks);\n });\n } catch (error) {\n if (error instanceof ToolNotFoundError) {\n return [];\n }\n throw error;\n }\n\n return result.created\n .map((block) => getById(block.id))\n .filter((node): node is BlockNode => node !== null);\n };\n\n /**\n * Insert one child block under `parentId` at flat `insertIndex`, atomically.\n * Delegates to core's `insertInsideParent`, which groups the block creation\n * AND the parent assignment into a single undo entry itself — so this is NOT\n * wrapped in the hook's `transact` (that would be a redundant nested group).\n * A dangling parentId is a no-op (null), mirroring `insert`'s parent guard;\n * an unknown child tool throws a typed ToolNotFoundError from core's compose\n * path — honor the null contract and re-throw anything else (genuine bug).\n */\n const insertInsideParent = (\n parentId: string,\n insertIndex: number,\n childData?: BlockToolData\n ): BlockNode | null => {\n // Silent existence probe (NOT getBlockIndex, which warns on unknown ids).\n if (getById(parentId) === null) {\n return null;\n }\n\n const created = ((): { id: string } | null | undefined => {\n try {\n return editor.blocks.insertInsideParent(parentId, insertIndex, childData);\n } catch (error) {\n if (error instanceof ToolNotFoundError) {\n return null;\n }\n throw error;\n }\n })();\n\n return created === undefined || created === null ? null : getById(created.id);\n };\n\n /**\n * Replace the whole document with saved {@link OutputData} — a document-LOAD\n * primitive (clears existing content first), the counterpart of the additive\n * {@link insertOutputData}. Pure delegation to core's async `render`.\n */\n const render = (data: OutputData): Promise<void> => editor.blocks.render(data);\n\n /** Remove every block — document reset. Pure delegation to core's async `clear`. */\n const clear = (): Promise<void> => editor.blocks.clear();\n\n /**\n * Serialize the document to Markdown — the read-side twin of\n * {@link UseBlocksApi.insertMarkdown}. Pure delegation to core's async\n * `exportMarkdown` (which lazy-loads the serializer).\n */\n const exportMarkdown = (): Promise<string> => editor.blocks.exportMarkdown();\n\n /**\n * The LIVE Yjs-sync flag, read at call time (the api handle is memoized, so a\n * cached property would go stale). Pure delegation to core's read-only flag.\n */\n const isSyncingFromYjs = (): boolean => {\n onRead();\n\n return editor.blocks.isSyncingFromYjs;\n };\n\n // Every key is listed EXPLICITLY — do NOT spread `...EMPTY_API` here. The\n // return is typed `UseBlocksApi`, so an explicit list makes a forgotten live\n // wiring a COMPILE error (missing property). Spreading EMPTY_API would instead\n // backfill the missing key with its pre-ready no-op stub, silently shipping a\n // method that does nothing when the editor IS ready — a hole no key-presence\n // test can catch (the key is present, just wrong). Keep it exhaustive.\n return {\n getById,\n getChildren,\n insert,\n insertMany,\n insertTree,\n insertMarkdown,\n exportMarkdown,\n move,\n nest,\n unnest,\n remove,\n update,\n convert,\n transact,\n transactWithoutCapture,\n getBlocksCount,\n getCurrentBlockIndex,\n getBlockByIndex,\n getBlockByElement,\n getBlockData,\n getBlockIndex,\n composeBlockData,\n renderFromHTML,\n insertOutputData,\n splitBlock,\n insertInsideParent,\n render,\n clear,\n isSyncingFromYjs,\n };\n};\n","import type { ReadOnlyModeConfig } from '@bloklabs/core';\n\n/**\n * Normalized shape of the `readOnly` config option\n */\nexport interface NormalizedReadOnlyConfig {\n enabled: boolean;\n hideControls: boolean;\n}\n\n/**\n * Single source of truth for interpreting the `readOnly` config option.\n * The object form always means read-only is enabled.\n * @param value - raw `readOnly` value from BlokConfig\n */\nexport function normalizeReadOnlyConfig(value: boolean | ReadOnlyModeConfig | undefined): NormalizedReadOnlyConfig {\n if (typeof value === 'object' && value !== null) {\n return { enabled: true, hideControls: value.hideControls === true };\n }\n\n return { enabled: value === true, hideControls: false };\n}\n","/**\n * Structural deep equality for JSON-like values (Blok `OutputData`).\n *\n * Framework-agnostic: shared by the React and Angular adapters to dedupe\n * reactive `data` updates so identical content does not trigger a redundant\n * re-render that would clobber the caret/selection. Handles the value shapes\n * that appear in editor data: plain objects, arrays, and primitives (including\n * `null`/`undefined`).\n * @param a - first value to compare\n * @param b - second value to compare\n * @returns true when both values are structurally equal\n */\nexport function deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) {\n return true;\n }\n\n if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null) {\n return false;\n }\n\n const aIsArray = Array.isArray(a);\n const bIsArray = Array.isArray(b);\n\n if (aIsArray !== bIsArray) {\n return false;\n }\n\n if (aIsArray && bIsArray) {\n if (a.length !== b.length) {\n return false;\n }\n\n return a.every((item, index) => deepEqual(item, b[index]));\n }\n\n const aObj = a as Record<string, unknown>;\n const bObj = b as Record<string, unknown>;\n const aKeys = Object.keys(aObj);\n const bKeys = Object.keys(bObj);\n\n if (aKeys.length !== bKeys.length) {\n return false;\n }\n\n return aKeys.every(\n (key) => Object.prototype.hasOwnProperty.call(bObj, key) && deepEqual(aObj[key], bObj[key])\n );\n}\n","import type { LooseOutputBlockData, LooseOutputData, OutputBlockData, OutputData } from '@bloklabs/core';\n/**\n * Public utilities for working with saved editor documents (`OutputData`).\n *\n * Consumers persisting editor content need two recurring predicates that the\n * editor itself already relies on internally:\n *\n * - structural equality, to dedupe the `data → render → onSave → data` echo\n * round-trip without clobbering the caret;\n * - emptiness, to decide whether a document carries any user content\n * (placeholder states, \"save\" button gating, skipping empty submissions).\n *\n * Both accept the loose wire shape (`data: null`, `id: null`, `parent: null`,\n * `content: null`, nullish documents) so backend DTOs can be passed as-is.\n */\nimport { deepEqual } from './deep-equal';\n\n\ntype AnyOutputData = OutputData | LooseOutputData | null | undefined;\n\n/**\n * Normalizes one block from the loose wire shape into the strict saved shape.\n * The single definition of how the wire spells \"absent\": `null`/`''` ids and\n * parents, `null`/`[]` content, `null`/missing data. Shared by\n * {@link normalizeOutputBlocks} and {@link equalsOutputBlock} so a DTO and its\n * saved echo are judged under the same rules.\n * @param block - a block in either the strict or the loose wire shape\n * @returns the block in the strict saved shape\n */\nfunction normalizeOutputBlock(block: OutputBlockData | LooseOutputBlockData): OutputBlockData {\n const { id, data, parent, content, ...rest } = block;\n\n return {\n ...rest,\n ...(typeof id === 'string' && id !== '' ? { id } : {}),\n ...(typeof parent === 'string' && parent !== '' ? { parent } : {}),\n ...(Array.isArray(content) && content.length > 0 ? { content } : {}),\n data: data ?? {},\n };\n}\n\n/**\n * Compares two blocks structurally. Both sides are normalized first\n * ({@link normalizeOutputBlock}), so the loose wire spellings of \"absent\"\n * (`parent: null`, `content: null`, `data: null`) equal the saved shape that\n * omits them. The `id` participates only when BOTH blocks carry one: the editor\n * mints a fresh id whenever content arrives without one, so an id-less origin\n * document must still compare equal to its saved echo.\n *\n * Edit metadata (`lastEditedAt`/`lastEditedBy`) never participates: it records\n * WHO touched the block and WHEN, not what it says, so a document whose only\n * delta is a stamp is not a content change.\n * @param a - first block to compare\n * @param b - second block to compare\n * @returns true when the blocks are structurally equal\n */\nfunction equalsOutputBlock(\n a: OutputBlockData | LooseOutputBlockData,\n b: OutputBlockData | LooseOutputBlockData\n): boolean {\n const { id: idA, lastEditedAt: _editedAtA, lastEditedBy: _editedByA, ...restA } = normalizeOutputBlock(a);\n const { id: idB, lastEditedAt: _editedAtB, lastEditedBy: _editedByB, ...restB } = normalizeOutputBlock(b);\n\n const hasIdA = typeof idA === 'string' && idA !== '';\n const hasIdB = typeof idB === 'string' && idB !== '';\n\n if (hasIdA && hasIdB && idA !== idB) {\n return false;\n }\n\n return deepEqual(restA, restB);\n}\n\n/**\n * The tool a pristine editor seeds its first (empty) block with. An empty block\n * of this type is UI scaffolding, not user content — see\n * {@link EqualsOutputDataOptions.ignoreEmptyDefaultBlocks}.\n */\nconst DEFAULT_BLOCK_TYPE = 'paragraph';\n\n/**\n * Options for {@link equalsOutputData}.\n */\nexport interface EqualsOutputDataOptions {\n /**\n * Ignore empty default blocks on both sides before comparing. A fresh editor\n * always seeds one empty default paragraph, so a pristine document\n * (`[{ type: 'paragraph', data: { text: '' } }]`) does not content-equal a\n * saved-empty baseline (`[]`) by default. Turn this on for dirty-vs-baseline\n * checks (\"has the user actually typed anything?\"): empty blocks of the\n * default paragraph tool are dropped from both documents first, so pristine\n * scaffolding and trailing empty lines don't register as a change. Empty\n * NON-default blocks (a content-less divider, an empty image) are kept — they\n * are meaningful content.\n */\n ignoreEmptyDefaultBlocks?: boolean;\n}\n\n/**\n * True for an empty block of the default paragraph tool — the editor's own\n * scaffolding, not user content.\n * @param block - block to inspect\n * @returns true when the block is an empty default paragraph\n */\nfunction isEmptyDefaultBlock(block: OutputBlockData | LooseOutputBlockData): boolean {\n return block.type === DEFAULT_BLOCK_TYPE && isEmptyValue(block.data);\n}\n\n/**\n * Resolves the blocks to compare for a document, dropping empty default blocks\n * when {@link EqualsOutputDataOptions.ignoreEmptyDefaultBlocks} is set.\n * @param data - document whose blocks are collected\n * @param options - comparison options\n * @returns the blocks to compare\n */\nfunction comparableBlocks(\n data: AnyOutputData,\n options?: EqualsOutputDataOptions\n): Array<OutputBlockData | LooseOutputBlockData> {\n const blocks = data?.blocks ?? [];\n\n if (options?.ignoreEmptyDefaultBlocks === true) {\n return blocks.filter((block) => !isEmptyDefaultBlock(block));\n }\n\n return blocks;\n}\n\n/**\n * Structural equality for saved documents. Compares the `blocks` arrays\n * deeply; the volatile `time` and `version` envelope fields are ignored, so a\n * document round-tripped through `save()` compares equal to its echo. Block\n * ids are compared only when both sides carry one — the editor mints fresh\n * ids for id-less content, so a legacy document still equals its saved echo.\n * Edit metadata (`lastEditedAt`/`lastEditedBy`) is ignored for the same reason:\n * it records who touched a block and when, not what it says. Nullish documents\n * compare equal to `{ blocks: [] }`.\n *\n * Pass `{ ignoreEmptyDefaultBlocks: true }` for dirty-vs-baseline checks so a\n * pristine editor (one empty default paragraph) equals a saved-empty baseline —\n * see {@link EqualsOutputDataOptions}.\n * @param a - first document to compare\n * @param b - second document to compare\n * @param options - comparison options\n * @returns true when both documents hold structurally equal blocks\n */\nexport function equalsOutputData(a: AnyOutputData, b: AnyOutputData, options?: EqualsOutputDataOptions): boolean {\n const blocksA = comparableBlocks(a, options);\n const blocksB = comparableBlocks(b, options);\n\n return blocksA.length === blocksB.length && blocksA.every((block, index) => equalsOutputBlock(block, blocksB[index]));\n}\n\n/**\n * A bounded window of the editor's recently emitted `onSave` payloads, used by\n * the framework adapters to recognize controlled-`data` echoes. Deduping\n * against only the LAST emitted payload is not enough: a host that persists on\n * save and refetches can hand the adapter a STALE echo — an earlier save\n * arriving after a newer one already replaced the baseline — and re-rendering\n * it would clobber the caret and any content typed since. Matching is\n * structural ({@link equalsOutputData}), so envelopes reshaped in transit\n * (fresh `time`, stripped ids) still count as echoes.\n * @param capacity - number of payloads retained before the oldest is evicted\n * @returns the echo window\n */\nexport function createEmittedEchoWindow(capacity: number = 20): {\n /** Records a payload the editor emitted via `onSave`. */\n record(data: OutputData | LooseOutputData): void;\n /** True when the document content-equals any recorded payload. */\n matches(data: AnyOutputData): boolean;\n /** Forgets all recorded payloads (external content took over). */\n clear(): void;\n} {\n const emitted: Array<OutputData | LooseOutputData> = [];\n\n return {\n record(data: OutputData | LooseOutputData): void {\n emitted.push(data);\n if (emitted.length > capacity) {\n emitted.shift();\n }\n },\n matches(data: AnyOutputData): boolean {\n return emitted.some((payload) => equalsOutputData(payload, data));\n },\n clear(): void {\n emitted.length = 0;\n },\n };\n}\n\n/**\n * A shared, deeply frozen empty document. Consumers persisting editor content\n * repeatedly hand-write `{ blocks: [] }` for cleared/pristine baselines; this\n * is the canonical value to use instead. Frozen (blocks array included) so a\n * shared reference can never be mutated into a stale non-empty baseline.\n */\nexport const EMPTY_OUTPUT_DATA: OutputData = Object.freeze({\n // Freeze the array too, so a shared reference can't be mutated. The public\n // `blocks` type is mutable (`OutputBlockData[]`), so the frozen (readonly)\n // array is re-widened through `unknown` — runtime stays frozen.\n blocks: Object.freeze([]) as unknown as OutputBlockData[],\n});\n\n/**\n * Maps a controlled `data` value to something the editor's `render()` accepts.\n * A whole-document `null` — a controlled \"clear to empty\" — becomes\n * `{ blocks: [] }`; any real document passes through untouched.\n *\n * The framework adapters (React/Vue/Angular) route their reactive `data` path\n * through this so a `null` never reaches `render()`, whose strict guard reads\n * `data.blocks` and would throw on `null`. `undefined` (uncontrolled) is handled\n * by the adapters before this point, so it is intentionally not an input here.\n * @param data - a controlled document, or `null` for an empty document\n * @returns a document `render()` can consume\n */\nexport function toRenderableData(data: OutputData | LooseOutputData | null): OutputData | LooseOutputData {\n return data === null ? { blocks: [] } : data;\n}\n\n/**\n * Normalizes blocks from the loose wire shape into the strict saved shape at\n * the editor's input boundaries: a `null`/missing `data` becomes `{}`, a\n * `null`/empty `id` is dropped so the block factory generates a fresh one, and\n * nullish/empty hierarchy references (`parent`, `content`) are dropped so a\n * root-level, childless block is spelled the one way the editor and `save()`\n * both spell it — absent. Idempotent — strict blocks pass through unchanged\n * (shallow-copied).\n * @param blocks - blocks in either the strict or the loose wire shape\n * @returns blocks in the strict saved shape\n */\nexport function normalizeOutputBlocks(blocks: Array<OutputBlockData | LooseOutputBlockData>): OutputBlockData[] {\n return blocks.map(normalizeOutputBlock);\n}\n\n/**\n * Normalizes a whole loose wire document into the strict saved\n * {@link OutputData} shape at an input boundary. A nullish document becomes\n * `{ blocks: [] }`; `null` envelope fields (`time`/`version`) are dropped and a\n * non-empty `id` is kept; each\n * block is passed through {@link normalizeOutputBlocks}, so `null`/missing\n * `data` becomes `{}`, `null`/empty ids are dropped for regeneration and\n * nullish/empty `parent`/`content` references are dropped as absent.\n *\n * Unlike a hand-written `blocks.map(...)` mapper, this preserves every block\n * passthrough field — `tunes`, real `parent`/`content` references, `indent`,\n * edit metadata — so a backend DTO can be turned into strict `OutputData`\n * without silently losing hierarchy or tunes. Idempotent: a strict document\n * passes through unchanged (shallow-copied).\n * @param data - a document in the strict or loose wire shape, or nullish\n * @returns the document in the strict saved shape\n */\nexport function normalizeOutputData(data: AnyOutputData): OutputData {\n if (data === null || data === undefined) {\n return { blocks: [] };\n }\n\n return {\n ...(typeof data.id === 'string' && data.id !== '' ? { id: data.id } : {}),\n ...(typeof data.version === 'string' ? { version: data.version } : {}),\n ...(typeof data.time === 'number' ? { time: data.time } : {}),\n blocks: normalizeOutputBlocks(data.blocks),\n };\n}\n\n/**\n * True when the value carries no user content: blank/whitespace-only strings,\n * empty arrays, plain objects whose values are all empty, and nullish values.\n * Numbers and booleans are presentation metadata (`level`, `checked`, styles)\n * and never count as content on their own.\n * @param value - block data value to inspect\n * @returns true when the value carries no user content\n */\nfunction isEmptyValue(value: unknown): boolean {\n if (value === null || value === undefined) {\n return true;\n }\n\n if (typeof value === 'string') {\n return value.trim() === '';\n }\n\n if (Array.isArray(value)) {\n return value.every(isEmptyValue);\n }\n\n if (typeof value === 'object') {\n return Object.values(value).every(isEmptyValue);\n }\n\n // Numbers, booleans and other primitives are metadata, not content.\n return true;\n}\n\n/**\n * True when the document carries no user content: it is nullish, has no\n * blocks, or every block's data holds only empty values (see\n * {@link isEmptyValue}). Note that content-less visual blocks (e.g. a divider,\n * whose data is `{}`) count as empty — check `blocks.length` when mere block\n * presence matters.\n * @param data - document to inspect\n * @returns true when the document carries no user content\n */\nexport function isEmptyOutputData(data: AnyOutputData): boolean {\n const blocks = data?.blocks ?? [];\n\n return blocks.every((block) => isEmptyValue(block.data));\n}\n","// src/shared/prop-schema.ts\n\n/** One field of a block's prop schema. */\nexport interface PropSchemaEntry {\n /** Default value, used when the incoming data omits this key. */\n default: unknown;\n /** Optional allowed values (advisory; not enforced at runtime in v1). */\n values?: readonly unknown[];\n}\n\n/**\n * Declarative data shape. The keys here are EXACTLY the keys `save()` returns to\n * Yjs — this closes the per-key-sync key-resurrection gap (a cleared field is\n * written as its explicit default, never dropped).\n */\nexport type PropSchema = Record<string, PropSchemaEntry>;\n\n/**\n * Fill a data object against the schema: every schema key present, incoming\n * value when defined else the schema default, and ONLY schema keys (so `save()`\n * is never partial). Returns a frozen plain object — safe to hand straight to\n * core's per-key Yjs sync.\n */\nexport const fillDefaults = <Data>(\n schema: PropSchema,\n data: Record<string, unknown>\n): Readonly<Data> => {\n const result: Record<string, unknown> = {};\n\n for (const key of Object.keys(schema)) {\n result[key] = data[key] !== undefined ? data[key] : schema[key].default;\n }\n\n return Object.freeze(result) as Readonly<Data>;\n};\n","/**\n * Centralized data attributes used across the Blok editor.\n * This is the single source of truth for all data-blok-* attributes.\n *\n * Exported as Blok.DATA_ATTR for users.\n *\n * Naming convention:\n * - Remove 'data-blok-' prefix and convert to camelCase\n * - Global attributes: hidden, disabled, focused\n * - Component prefixed: popover, popoverItem, toolbar, etc.\n */\nexport const DATA_ATTR = {\n // ============================================\n // Core Element Identifiers\n // ============================================\n\n /** Interface type identifier (blok, inline-toolbar, tooltip) */\n interface: 'data-blok-interface',\n /** Block element wrapper */\n element: 'data-blok-element',\n /** Block element content wrapper */\n elementContent: 'data-blok-element-content',\n /** Editor wrapper container */\n editor: 'data-blok-editor',\n /** Per-instance discriminator on the editor wrapper (a monotonic counter, as a\n * string). Two editors on one page share every other scope attribute, so this\n * is what lets a page-level stylesheet — Blok's own injected `style.fontSize`\n * sheet, or a host rule — address ONE editor. Public styling hook. */\n instance: 'data-blok-instance',\n /** Redactor zone */\n redactor: 'data-blok-redactor',\n /** Present on the editor wrapper once a `blocks.render()` batch has finished\n * inserting blocks into the DOM; removed while a re-render is in flight.\n * Acts as a stable render-readiness gate for consumers (e.g. E2E waits). */\n rendered: 'data-blok-rendered',\n /** Present on the editor wrapper while the loading skeleton owns it.\n * Public styling hook. */\n loading: 'data-blok-loading',\n /** The loading skeleton overlay (a wrapper child, never inside the redactor). */\n loadingSkeleton: 'data-blok-loading-skeleton',\n /** One skeleton row; the value is its kind: heading | paragraph | list. */\n skeletonBar: 'data-blok-skeleton-bar',\n /** Blok version number stamped on the editor wrapper (e.g. '1.10.0', 'dev').\n * Consumed by browser extensions to identify the running version. */\n version: 'data-blok-version',\n\n // ============================================\n // Block Identifiers\n // ============================================\n\n /** Block unique identifier */\n id: 'data-blok-id',\n pageId: 'data-blok-page-id',\n /** Block component/tool type */\n component: 'data-blok-component',\n /** Tool type attribute */\n tool: 'data-blok-tool',\n blockContextMenu: 'data-blok-block-context-menu',\n /** Block nesting depth (derived from the parentId chain) */\n depth: 'data-blok-depth',\n /** Flat list-nesting indentation level (0 = root); tool-agnostic, mirrors list depth */\n indent: 'data-blok-indent',\n /** Header tool's heading level (1-6). Public styling hook — keyed by level rather\n * than by tag name, so a level remapped to a custom tag via `levelOverrides[n].tag`\n * (types/tools/header.d.ts) still matches its level's typography rules. */\n headingLevel: 'data-blok-heading-level',\n\n // ============================================\n // Global States\n // ============================================\n\n /** Element is hidden from view */\n hidden: 'data-blok-hidden',\n /** Element is disabled and non-interactive */\n disabled: 'data-blok-disabled',\n /** Element is focused via keyboard navigation */\n focused: 'data-blok-focused',\n /** On a popover once a navigation key moved its cursor; gates the focus ring */\n keyboardNavigated: 'data-blok-keyboard-navigated',\n /** Block is selected */\n selected: 'data-blok-selected',\n /** On a block's spotlight target while it is being pointed out (Show in the failed-image notice) */\n spotlight: 'data-blok-spotlight',\n /** Marks the element inside a block that Show points at, e.g. the image's error card */\n spotlightTarget: 'data-blok-spotlight-target',\n /** Marks the control inside a spotlight target that receives focus, e.g. Retry */\n spotlightFocus: 'data-blok-spotlight-focus',\n /** Block is stretched */\n stretched: 'data-blok-stretched',\n /** Editor or element is empty */\n empty: 'data-blok-empty',\n /** Present on the editor wrapper while read-only mode is active.\n * Public styling hook — lets hosts key rules off the editing state\n * without JS. Deliberately does NOT collapse the gutter: plain\n * read-only still shows the block-hover copy-link control there, and\n * in-place readOnly.set() flips must not shift the layout. */\n readonly: 'data-blok-readonly',\n /** Present on the editor wrapper while read-only mode hides ALL editor\n * controls (readOnly: { hideControls: true }). Public styling hook —\n * drives the gutter auto-collapse for genuinely chromeless read-only. */\n controlsHidden: 'data-blok-controls-hidden',\n /** Present on the editor wrapper when config.hideToolbar is true.\n * Public styling hook — drives the gutter auto-collapse (the gutter\n * exists solely to house the toolbar's +/⠿ controls). */\n toolbarHidden: 'data-blok-toolbar-hidden',\n /** Which gutter the floating block controls occupy: 'left' (default,\n * inline-start) or 'right' (inline-end). Written on the editor wrapper from\n * config.toolbarPosition and kept in sync by `toolbar.setPosition()`.\n * Public styling hook — drives the gutter swap and the actions-bar side. */\n toolbarPosition: 'data-blok-toolbar-position',\n\n // ============================================\n // Editor Modes\n // ============================================\n\n /** Content alignment mode (left, center, right) */\n contentAlign: 'data-blok-content-align',\n /** Right-to-left mode */\n rtl: 'data-blok-rtl',\n /** Editor content width mode (present with value \"full\" for wide mode; absent = narrow) */\n width: 'data-blok-width',\n /** Present on the editor wrapper when config.style.nativeSelection is true.\n * Public styling hook — disables Blok's ::selection repaint (preflight.css)\n * and re-points the fake-background highlight at the UA Highlight color\n * (colors.css), so selection falls back to native/host-defined colors. */\n nativeSelection: 'data-blok-native-selection',\n /** Present on the editor wrapper while a cross-block TEXT selection is painted.\n * Suppresses the engine's own ::selection paint (main.css) so the\n * ::highlight() sub-ranges are the only thing drawn — Chromium and Firefox\n * paint such a range natively too and would otherwise double it up. */\n crossSelection: 'data-blok-cross-selection',\n\n // ============================================\n // Drag and Drop\n // ============================================\n\n /** Block is being dragged */\n dragging: 'data-blok-dragging',\n /** Multiple blocks being dragged */\n draggingMulti: 'data-blok-dragging-multi',\n /** Block is being duplicated (Alt+drag) */\n duplicating: 'data-blok-duplicating',\n /** Drag handle element */\n dragHandle: 'data-blok-drag-handle',\n\n // ============================================\n // Toolbar\n // ============================================\n\n /** Toolbar element */\n toolbar: 'data-blok-toolbar',\n /** The floating block-controls bar (plus button + drag/settings handle)\n * inside the toolbar. Public styling hook — the side it docks to is driven\n * from the wrapper's `data-blok-toolbar-position`. */\n toolbarActions: 'data-blok-toolbar-actions',\n /** Settings toggler button */\n settingsToggler: 'data-blok-settings-toggler',\n /** Toolbox is open */\n toolboxOpened: 'data-blok-toolbox-opened',\n /** Block settings is open */\n blockSettingsOpened: 'data-blok-block-settings-opened',\n /** Element is opened (generic) */\n opened: 'data-blok-opened',\n\n // ============================================\n // Popover Container\n // ============================================\n\n /** Root popover element */\n popover: 'data-blok-popover',\n /** Popover container wrapper */\n popoverContainer: 'data-blok-popover-container',\n /** Popover items list */\n popoverItems: 'data-blok-popover-items',\n /** Custom, engine-independent scrollbar thumb overlaid on the popover items */\n popoverScrollbar: 'data-blok-popover-scrollbar',\n /** Stamped on the custom scrollbar thumb while it is being dragged (keeps it revealed) */\n popoverScrollbarDragging: 'data-blok-dragging',\n /** Stamped on a scroll container while it is actively scrolling (reveals the auto-hidden scrollbar thumb) */\n scrolling: 'data-blok-scrolling',\n /** Popover overlay element */\n popoverOverlay: 'data-blok-popover-overlay',\n /** Popover custom content area */\n popoverCustomContent: 'data-blok-popover-custom-content',\n /** Popover custom class */\n popoverCustomClass: 'data-blok-popover-custom-class',\n /** Inline popover variant */\n popoverInline: 'data-blok-popover-inline',\n /** Popover is open */\n popoverOpened: 'data-blok-popover-opened',\n /** Popover opens upward */\n popoverOpenTop: 'data-blok-popover-open-top',\n /** Popover opens leftward */\n popoverOpenLeft: 'data-blok-popover-open-left',\n\n // ============================================\n // Popover Nesting\n // ============================================\n\n /** Nested popover indicator */\n nested: 'data-blok-nested',\n /** Nesting level value */\n nestedLevel: 'data-blok-nested-level',\n /** Group label for promoted search results from nested children */\n promotedGroupLabel: 'data-blok-promoted-group-label',\n /** A nested child shown in the host menu's search results. The convert-menu styles skip it, so the host keeps its own layout. */\n promotedItem: 'data-blok-promoted-item',\n /** Group label for top-level matches in search results */\n topLevelGroupLabel: 'data-blok-top-level-group-label',\n\n // ============================================\n // Popover Header\n // ============================================\n\n /** Header container */\n popoverHeader: 'data-blok-popover-header',\n /** Header text element */\n popoverHeaderText: 'data-blok-popover-header-text',\n /** Back button in nested popover */\n popoverHeaderBackButton: 'data-blok-popover-header-back-button',\n\n // ============================================\n // Popover Items\n // ============================================\n\n /** Item container */\n popoverItem: 'data-blok-popover-item',\n /** Item icon wrapper */\n popoverItemIcon: 'data-blok-popover-item-icon',\n /** Chevron icon for nested items */\n popoverItemIconChevronRight: 'data-blok-popover-item-icon-chevron-right',\n /** Item title text */\n popoverItemTitle: 'data-blok-popover-item-title',\n /** Item secondary title */\n popoverItemSecondaryTitle: 'data-blok-popover-item-secondary-title',\n /** Item is active/selected */\n popoverItemActive: 'data-blok-popover-item-active',\n /** Item's child menu is currently open — keeps the trigger looking selected */\n popoverItemChildrenOpen: 'data-blok-popover-item-children-open',\n /** Confirmation state */\n popoverItemConfirmation: 'data-blok-popover-item-confirmation',\n /** Disable hover styling */\n popoverItemNoHover: 'data-blok-popover-item-no-hover',\n /** Disable focus handling */\n popoverItemNoFocus: 'data-blok-popover-item-no-focus',\n /** Destructive action item (e.g. delete) */\n popoverItemDestructive: 'data-blok-popover-item-destructive',\n /** Separator item */\n popoverItemSeparator: 'data-blok-popover-item-separator',\n /** Separator line element */\n popoverItemSeparatorLine: 'data-blok-popover-item-separator-line',\n /** HTML-based item */\n popoverItemHtml: 'data-blok-popover-item-html',\n /** Item has child menu */\n hasChildren: 'data-blok-has-children',\n /** Item name identifier */\n itemName: 'data-blok-item-name',\n /** No search results shown */\n nothingFoundDisplayed: 'data-blok-nothing-found-displayed',\n\n // ============================================\n // Overlay / Selection\n // ============================================\n\n /** Selection overlay */\n overlay: 'data-blok-overlay',\n /** Overlay container */\n overlayContainer: 'data-blok-overlay-container',\n /** Selection rectangle */\n overlayRectangle: 'data-blok-overlay-rectangle',\n /** Overlay is hidden */\n overlayHidden: 'data-blok-overlay-hidden',\n /** Fake cursor indicator */\n fakeCursor: 'data-blok-fake-cursor',\n /** Fake background for selection */\n fakeBackground: 'data-blok-fake-background',\n\n // ============================================\n // Scroll\n // ============================================\n\n /** Auto-scroll zone (top/bottom) */\n scrollZone: 'data-blok-scroll-zone',\n /** Scroll is locked */\n scrollLocked: 'data-blok-scroll-locked',\n /** Hard scroll lock */\n scrollLockedHard: 'data-blok-scroll-locked-hard',\n\n // ============================================\n // Caret\n // ============================================\n\n /** Shadow caret element */\n shadowCaret: 'data-blok-shadow-caret',\n\n // ============================================\n // Placeholders\n // ============================================\n\n /** Placeholder text */\n placeholder: 'data-blok-placeholder',\n /** Active placeholder text */\n placeholderActive: 'data-blok-placeholder-active',\n\n // ============================================\n // Columns Layout\n // ============================================\n\n /** The columns row rendered by the column_list tool (the flex container).\n * Public styling hook — its direct `[data-blok-element]` children are the\n * column holders, whose shrink floor reads `--blok-column-min-width` and\n * whose gutter reads `--blok-column-gutter`. */\n columns: 'data-blok-columns',\n /** A single column inside a columns row. */\n column: 'data-blok-column',\n /** Drag-to-resize separator between two adjacent columns. Present only in\n * edit mode — the separators ARE the gutter there. */\n columnResizer: 'data-blok-column-resizer',\n /** Present on a columns row whose gutter comes from the container's own\n * column-gap instead of from resizer elements. Set in read-only mode, where\n * no resizers are built — the discriminator between an editable row and a\n * published one. */\n columnsStaticGutter: 'data-blok-columns-static-gutter',\n\n // ============================================\n // Nested Blocks\n // ============================================\n\n /** Container that hosts nested block holders (table cells, toggle/callout/header children).\n * Used as a universal guard: before moving a block holder via appendChild,\n * check `holder.closest([nestedBlocks])` — if truthy, the holder is already\n * claimed by another container and must not be stolen. */\n nestedBlocks: 'data-blok-nested-blocks',\n\n /** A drop zone. Empty value: an empty container's placeholder (an empty\n * tab); while the block's own holder shows one without the `hidden` class,\n * a drop on the block nests the dragged blocks as its first children.\n * A block id (a tab pill): a drop on the zone appends the dragged blocks\n * as the LAST children of that block. */\n dropInto: 'data-blok-drop-into',\n\n /** Set by core on a named drop zone while it is the drop target. */\n dropIntoActive: 'data-blok-drop-into-active',\n\n /** A container's empty-state hint that stands in for its first child block\n * (empty tab, empty toggle body). It is not a block, so hovering or pressing\n * it shows no block toolbar; the block a click creates gets its own. */\n childStandIn: 'data-blok-child-stand-in',\n\n // ============================================\n // Mutation Tracking\n // ============================================\n\n /** Element excluded from mutation tracking */\n mutationFree: 'data-blok-mutation-free',\n\n // ============================================\n // Tool Chrome\n // ============================================\n\n /** Tool UI inside a block that is not the user's content (a list marker, a\n * checkbox, a code block's language button and line numbers). `Block.isEmpty`\n * and the block's copied HTML skip it. Never put it on an element that holds\n * child blocks or the user's text: that content would be skipped too. */\n chrome: 'data-blok-chrome',\n\n // ============================================\n // Keyboard Ownership\n // ============================================\n\n /** Marks a subtree whose keyboard belongs to the Tool that rendered it, not to\n * the editor. Blok's block-level keydown/keyup handling stands down entirely\n * for events originating inside it — Escape, Tab, the arrows, \"/\" and the\n * Enter/Backspace/Delete structural keys all reach the element untouched.\n *\n * Blok already exempts native `<input>`/`<textarea>` from the STRUCTURAL keys\n * (Enter/Backspace/Delete and \"/\") because those are contenteditable-shaped\n * and would splice the document around a form field. Escape/Tab/arrows are\n * deliberately NOT exempt — they are how a user leaves a field. That default\n * is right for a one-line title input and wrong for a field with its own\n * keyboard semantics (Tab between sub-fields, Escape to cancel an edit, arrows\n * to walk a suggestion list), which is exactly what this attribute is for.\n * Public authoring hook. */\n keyboardOwner: 'data-blok-keyboard-owner',\n /** Marks a subtree whose links belong to the tool: Blok's link hover card\n * and link-click navigation stand down inside it. For a link the tool opens\n * and previews itself (the page block). Public authoring hook. */\n linkOwner: 'data-blok-link-owner',\n\n // ============================================\n // Navigation\n // ============================================\n\n /** Block has navigation focus */\n navigationFocused: 'data-blok-navigation-focused',\n /** Flipper navigation target */\n flipperNavigationTarget: 'data-blok-flipper-navigation-target',\n\n // ============================================\n // Inline Toolbar\n // ============================================\n\n /** Inline toolbar enabled on external element */\n inlineToolbar: 'data-blok-inline-toolbar',\n\n // ============================================\n // Link Tool\n // ============================================\n\n /** Link tool is active */\n linkToolActive: 'data-blok-link-tool-active',\n /** Link tool unlink mode */\n linkToolUnlink: 'data-blok-link-tool-unlink',\n /** Link tool input is opened */\n linkToolInputOpened: 'data-blok-link-tool-input-opened',\n\n // ============================================\n // Bold Tool\n // ============================================\n\n /** Bold collapsed length tracking */\n boldCollapsedLength: 'data-blok-bold-collapsed-length',\n /** Bold collapsed active state */\n boldCollapsedActive: 'data-blok-bold-collapsed-active',\n /** Bold previous length tracking */\n boldPrevLength: 'data-blok-bold-prev-length',\n /** Bold leading whitespace */\n boldLeadingWs: 'data-blok-bold-leading-ws',\n /** Bold marker */\n boldMarker: 'data-blok-bold-marker',\n\n // ============================================\n // Tooltip\n // ============================================\n\n /** Tooltip is shown */\n shown: 'data-blok-shown',\n /** Tooltip placement */\n placement: 'data-blok-placement',\n\n // ============================================\n // Notifier\n // ============================================\n\n /** Bounce in animation */\n bounceIn: 'data-blok-bounce-in',\n\n // ============================================\n // Announcer (Accessibility)\n // ============================================\n\n /** Live region announcer */\n announcer: 'data-blok-announcer',\n\n // ============================================\n // Stub Block\n // ============================================\n\n /** Stub block element */\n stub: 'data-blok-stub',\n /** Stub info section */\n stubInfo: 'data-blok-stub-info',\n /** Stub title */\n stubTitle: 'data-blok-stub-title',\n /** Stub subtitle */\n stubSubtitle: 'data-blok-stub-subtitle',\n\n // ============================================\n // Slash Search\n // ============================================\n\n /** Slash search active on content editable */\n slashSearch: 'data-blok-slash-search',\n\n // ============================================\n // Testing\n // ============================================\n\n /** Test identifier (for E2E tests) */\n testid: 'data-blok-testid',\n /** Force hover state (for tests/storybook) */\n forceHover: 'data-blok-force-hover',\n} as const;\n\n/**\n * Type for DATA_ATTR keys\n */\nexport type DataAttrKey = keyof typeof DATA_ATTR;\n\n/**\n * Type for DATA_ATTR values\n */\nexport type DataAttrValue = (typeof DATA_ATTR)[DataAttrKey];\n\n/**\n * Helper function to create a CSS selector from an attribute\n *\n * @param attr - The data attribute name from DATA_ATTR\n * @param value - Optional value for the attribute (defaults to presence selector)\n * @returns CSS selector string\n *\n * @example\n * createSelector(DATA_ATTR.element) // '[data-blok-element]'\n * createSelector(DATA_ATTR.selected, true) // '[data-blok-selected=\"true\"]'\n * createSelector(DATA_ATTR.tool, 'paragraph') // '[data-blok-tool=\"paragraph\"]'\n */\nexport const createSelector = (attr: DataAttrValue, value?: string | boolean): string => {\n if (value === undefined) {\n return `[${attr}]`;\n }\n\n return `[${attr}=\"${value}\"]`;\n};\n","/**\n * HTML manipulation utilities\n */\n\n/**\n * Strips editor-only wrapper elements from HTML content: the inline toolbar's\n * fake selection background and the slash menu's pill around \"/query\". The\n * block stays watched while the slash menu is open, so its saves see the pill.\n * @param html - HTML content that may contain those wrappers\n * @returns HTML content with the wrappers removed but their content preserved\n */\nexport const stripFakeBackgroundElements = (html: string): string => {\n if (!html || (!html.includes('data-blok-fake-background') && !html.includes('data-blok-slash-search'))) {\n return html;\n }\n\n const tempDiv = document.createElement('div');\n\n tempDiv.innerHTML = html;\n\n const fakeBackgrounds = tempDiv.querySelectorAll('[data-blok-fake-background=\"true\"], span[data-blok-slash-search]');\n\n fakeBackgrounds.forEach((element) => {\n const parent = element.parentNode;\n\n if (!parent) {\n return;\n }\n\n while (element.firstChild) {\n parent.insertBefore(element.firstChild, element);\n }\n\n parent.removeChild(element);\n });\n\n return tempDiv.innerHTML;\n};\n\n/**\n * An intersection rather than `interface extends Element`: TypeScript 6's\n * lib.dom.d.ts declares `moveBefore` as a required member of ParentNode, and an\n * interface may not redeclare an inherited member as optional. Intersections\n * skip that declaration-compatibility check, so this compiles on both the 5.9\n * libs (no `moveBefore` at all) and the 6.0 libs (required `moveBefore`).\n */\ntype StatefulMoveParent = Element & {\n moveBefore?(node: Node, reference: Node | null): void;\n};\n\n/**\n * Repositions an already-attached node within `parent`, inserting it before\n * `reference` (or at the end when `reference` is null), while preserving the\n * node's live state — an iframe keeps its loaded document, media keeps playing,\n * form fields keep focus and value.\n *\n * A plain insertBefore/appendChild detaches and re-attaches the node, which\n * resets exactly that state (re-parented iframes reload). The browser's\n * state-preserving move (`moveBefore`, Chrome 133+) avoids the detach; we fall\n * back to insertBefore where it is unavailable or throws (e.g. cross-document\n * moves, or a node that is not connected).\n */\nconst statefulMove = (parent: StatefulMoveParent, node: Node, reference: Node | null): void => {\n if (reference === node) {\n return;\n }\n\n if (typeof parent.moveBefore === 'function' && node.isConnected && parent.isConnected) {\n try {\n parent.moveBefore(node, reference);\n\n return;\n } catch {\n // moveBefore enforces stricter invariants than insertBefore (same\n // document, connected node); fall back to a plain, state-resetting insert.\n }\n }\n\n parent.insertBefore(node, reference);\n};\n\n/**\n * Moves `node` to sit immediately before `reference`, preserving live state.\n * @see statefulMove\n */\nexport const moveElementBefore = (node: Node, reference: Element): void => {\n const parent = reference.parentNode;\n\n if (parent instanceof Element) {\n statefulMove(parent, node, reference);\n }\n};\n\n/**\n * Moves `node` to sit immediately after `reference`, preserving live state.\n * @see statefulMove\n */\nexport const moveElementAfter = (node: Node, reference: Element): void => {\n const parent = reference.parentNode;\n\n if (parent instanceof Element) {\n statefulMove(parent, node, reference.nextSibling);\n }\n};\n\n/**\n * Moves `node` to the end of `parent`'s children, preserving live state.\n * @see statefulMove\n */\nexport const moveElementToEnd = (parent: Element, node: Node): void => {\n statefulMove(parent, node, null);\n};\n","import { DATA_ATTR } from '../components/constants/data-attributes';\nimport { moveElementBefore, moveElementToEnd } from '../components/utils/html';\n\n/**\n * The caret, captured as raw primitives.\n *\n * A Range cannot stand in for this: every Range is LIVE, so the removal a\n * non-preserving move performs relocates its boundary points out of the moved\n * subtree before they could be re-applied. The (node, offset) pairs read out\n * beforehand are the only thing that survives.\n */\ninterface CaretSnapshot {\n /** The focused element, when it sits inside the holder being moved. */\n focused: HTMLElement | null;\n /** Range start, when the range sits inside the holder being moved. */\n start: [Node, number] | null;\n /** Range end, matching {@link CaretSnapshot.start}. */\n end: [Node, number] | null;\n}\n\n/**\n * Captures focus + caret, but only the part of it that lives inside `holder` —\n * a selection anywhere else is none of this move's business and must be left\n * exactly as it is.\n * @param holder - the holder about to be moved\n * @returns the snapshot, or null when the caret is elsewhere\n */\nconst captureCaretWithin = (holder: HTMLElement): CaretSnapshot | null => {\n const ownerDocument = holder.ownerDocument;\n const activeElement = ownerDocument.activeElement;\n const focused =\n activeElement instanceof HTMLElement && holder.contains(activeElement) ? activeElement : null;\n\n const selection = ownerDocument.defaultView?.getSelection() ?? null;\n const range = selection !== null && selection.rangeCount > 0 ? selection.getRangeAt(0) : null;\n const rangeInside =\n range !== null && holder.contains(range.startContainer) && holder.contains(range.endContainer);\n\n if (focused === null && !rangeInside) {\n return null;\n }\n\n return {\n focused,\n start: rangeInside && range !== null ? [range.startContainer, range.startOffset] : null,\n end: rangeInside && range !== null ? [range.endContainer, range.endOffset] : null,\n };\n};\n\n/**\n * Re-applies a snapshot, but only where the move actually destroyed it —\n * a browser with the state-preserving move keeps focus and the caret itself,\n * and re-setting an identical range there would emit a spurious\n * `selectionchange` at every container render.\n * @param snapshot - what {@link captureCaretWithin} read, or null\n */\nconst restoreCaret = (snapshot: CaretSnapshot | null): void => {\n if (snapshot === null) {\n return;\n }\n\n const { focused, start, end } = snapshot;\n\n if (focused !== null && focused.isConnected && focused.ownerDocument.activeElement !== focused) {\n focused.focus({ preventScroll: true });\n }\n\n if (start === null || end === null || !start[0].isConnected) {\n return;\n }\n\n const ownerDocument = start[0].ownerDocument;\n const selection = ownerDocument?.defaultView?.getSelection() ?? null;\n\n if (ownerDocument === null || selection === null) {\n return;\n }\n\n const live = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;\n const intact =\n live !== null &&\n live.startContainer === start[0] &&\n live.startOffset === start[1] &&\n live.endContainer === end[0] &&\n live.endOffset === end[1];\n\n if (intact) {\n return;\n }\n\n const range = ownerDocument.createRange();\n\n range.setStart(start[0], start[1]);\n range.setEnd(end[0], end[1]);\n selection.removeAllRanges();\n selection.addRange(range);\n};\n\n/**\n * Every child slot carries one of these — first-party containers and every\n * adapter's `<BlockChildren>` alike. `BlockHierarchy` reads the same selector,\n * so the two sides agree on which blocks own a slot.\n */\nexport const CHILD_SLOT_SELECTOR = '[data-blok-toggle-children], [data-blok-nested-blocks]';\n\n/**\n * Parents that place their children themselves (per cell / per view). Their\n * descendants must never be pulled into an enclosing slot.\n */\nexport const SELF_PLACING_PARENTS: ReadonlySet<string> = new Set(['table', 'database']);\n\n/**\n * A slotless block renders its children as flat sibling holders right after\n * itself, in whatever slot holds the block — the same as nesting at root.\n * @param block - the block to test\n */\nexport const isSlotless = (block: { holder: HTMLElement; name?: string }): boolean =>\n block.holder.querySelector(CHILD_SLOT_SELECTOR) === null &&\n !SELF_PLACING_PARENTS.has(block.name ?? '');\n\n/**\n * The blocks a container slot hosts: its children, each followed by the\n * descendants of a slotless child (depth-first, flat order). A child that owns a\n * slot keeps its own descendants.\n * @param children - the container block's model children, in model order\n * @param getChildren - model children of a block, by id\n */\nexport const withSlotlessDescendants = <T extends { holder: HTMLElement; id?: string; name?: string }>(\n children: T[],\n getChildren: (id: string) => T[],\n): T[] => {\n // Keyed by holder: a malformed parent chain must not recurse forever.\n const seen = new Set<HTMLElement>();\n\n const expand = (list: T[]): T[] => list.flatMap((child) => {\n if (seen.has(child.holder)) {\n return [];\n }\n seen.add(child.holder);\n\n const nested = child.id !== undefined && isSlotless(child) ? expand(getChildren(child.id)) : [];\n\n return [child, ...nested];\n });\n\n return expand(children);\n};\n\n/**\n * Mount child block holders into a container, skipping children that are\n * already in place or claimed by another nested-blocks container.\n *\n * Used by toggle, header, column, and callout tools — and by the React, Vue and\n * Angular block adapters — to reconcile child holders during the `rendered()`\n * lifecycle hook. It is the standing DOM↔model reconciler for container blocks:\n * safe to call on every render, and the only thing that heals a child holder\n * that core parked outside the container while the container's own slot had not\n * been created yet.\n * @param container - the container element child holders belong in; usually the\n * element carrying `data-blok-nested-blocks`.\n * @param children - the container block's MODEL children, in model order (e.g.\n * `api.blocks.getChildren(blockId)`).\n */\nexport const mountChildBlocks = (\n container: HTMLElement,\n children: { holder: HTMLElement }[],\n): void => {\n /**\n * Places a holder at its MODEL position: before the first later child that is\n * already mounted here, or at the end when there is none. A plain appendChild\n * would put a reclaimed middle child last — children [A, B, C] with only B\n * stranded would render A, C, B.\n *\n * The move goes through the state-preserving helpers rather than raw\n * insertBefore/appendChild: re-parenting a live node runs the DOM removing\n * steps, which blur the focused contenteditable and relocate every live Range\n * out of the moved subtree — the user's caret vanishes to <body> mid-typing.\n * Where the browser has no state-preserving move, the caret is put back by\n * hand around the move.\n * @param holder - the holder to mount\n * @param index - the holder's position in `children`\n */\n const mountAtModelPosition = (holder: HTMLElement, index: number): void => {\n const anchor = children\n .slice(index + 1)\n .find(next => next.holder.parentElement === container)?.holder ?? null;\n\n const caret = captureCaretWithin(holder);\n\n anchor !== null ? moveElementBefore(holder, anchor) : moveElementToEnd(container, holder);\n\n restoreCaret(caret);\n };\n\n for (const [index, child] of children.entries()) {\n if (child.holder.parentElement === container) {\n continue;\n }\n\n const nested = child.holder.closest(`[${DATA_ATTR.nestedBlocks}]`);\n\n // Claim a holder stranded in an ANCESTOR nested container. Callers pass\n // this container's own MODEL children, and a container that ENCLOSES this\n // one can never be a legitimate home for them — that is model/DOM\n // divergence by definition. Two ways to get there: a drag reparent into a\n // column drops the moved holder directly into the [data-blok-columns] row\n // (where it renders as a rogue extra column), and a newly inserted first\n // child is anchored as the container block's DOM *sibling*, i.e. inside\n // whatever nested container encloses it — permanent when the destination\n // slot had not committed yet (a framework adapter's portal commits a render\n // later than core inserts), because nothing else ever re-runs the mount.\n if (nested !== null && nested !== container && nested.contains(container)) {\n mountAtModelPosition(child.holder, index);\n continue;\n }\n\n // Otherwise leave holders that already live inside another nested container\n // (a sibling, or a deeper nesting within this one) where they are.\n if (nested !== null) {\n continue;\n }\n\n mountAtModelPosition(child.holder, index);\n }\n};\n","import { DATA_ATTR } from '../components/constants/data-attributes';\n\n/**\n * One child's decoration: attribute name → value. `null`/`undefined` removes the\n * attribute; a boolean or number is stringified (so `false` writes\n * `data-active=\"false\"`, which CSS can select, rather than dropping the hook).\n */\nexport type ChildAttributes = Record<string, string | number | boolean | null | undefined>;\n\n/** The minimum a child must expose for a decoration pass. */\nexport interface DecoratableChild {\n id: string;\n holder: HTMLElement;\n}\n\n/**\n * A per-child decorator: what to write for the child at `index`.\n *\n * Generic over the child so an adapter can declare its decorators in terms of the\n * full `BlockAPI` its authors receive. A non-generic `(child: DecoratableChild)`\n * parameter would REJECT those: a function that demands a full BlockAPI is not\n * assignable to one promising to accept the structural minimum.\n */\nexport type ChildAttributesFn<Child extends DecoratableChild = DecoratableChild> = (\n child: Child,\n index: number\n) => ChildAttributes;\n\n/** What the previous decoration pass wrote for one child, so it can be undone. */\ninterface StampedChild {\n /** The element written to — a holder for one ledger, a content wrapper for the other. */\n target: HTMLElement;\n names: string[];\n}\n\n/** The ledgers a container keeps between passes; create one per child slot. */\nexport interface ChildDecorationLedger {\n holders: Map<string, StampedChild>;\n contents: Map<string, StampedChild>;\n}\n\n/**\n * A fresh pair of ledgers for one container's child slot.\n * @returns empty holder/content ledgers\n */\nexport const createChildDecorationLedger = (): ChildDecorationLedger => ({\n holders: new Map(),\n contents: new Map(),\n});\n\n/**\n * The child's OWN content wrapper, or null when its DOM has not committed yet.\n *\n * The first `[data-blok-element-content]` in document order under a holder is\n * always that block's own: a descendant block's wrapper necessarily sits INSIDE\n * it. Not `firstElementChild` — block tunes wrap the content node, so it is not\n * reliably a direct child (this is the same lookup core's own\n * `refreshToolRootElement` uses).\n * @param holder - the child block's holder\n * @returns the content wrapper, or null\n */\nconst contentWrapperOf = (holder: HTMLElement): HTMLElement | null =>\n holder.querySelector<HTMLElement>(`[${DATA_ATTR.elementContent}]`);\n\n/**\n * Apply one decoration pass and clear the previous pass's leftovers — including\n * on a child that has since left the container, which would otherwise keep a\n * dead index forever.\n * @param ledger - what the last pass wrote (mutated)\n * @param children - the container's model children, in model order\n * @param decorate - the per-child decorator for the child HOLDERS, if any\n * @param resolveTarget - which element of a child this pass writes to\n */\nconst applyPass = <Child extends DecoratableChild>(\n ledger: Map<string, StampedChild>,\n children: Child[],\n decorate: ChildAttributesFn<Child> | undefined,\n resolveTarget: (holder: HTMLElement) => HTMLElement | null\n): void => {\n const next = new Map<string, StampedChild>();\n\n children.forEach((child, index) => {\n const target = resolveTarget(child.holder);\n\n /**\n * A portal-rendered child commits its DOM a frame after core inserts it, so\n * its content wrapper can legitimately be missing on this pass. Skipping\n * (rather than throwing) leaves the next pass to stamp it.\n */\n if (target === null) {\n return;\n }\n\n const names: string[] = [];\n\n for (const [name, value] of Object.entries(decorate?.(child, index) ?? {})) {\n if (value === null || value === undefined) {\n target.removeAttribute(name);\n continue;\n }\n\n target.setAttribute(name, String(value));\n names.push(name);\n }\n\n next.set(child.id, { target, names });\n });\n\n for (const [id, previous] of ledger) {\n const current = next.get(id);\n\n previous.names\n .filter(name => current === undefined || !current.names.includes(name))\n .forEach(name => previous.target.removeAttribute(name));\n }\n\n ledger.clear();\n next.forEach((entry, id) => ledger.set(id, entry));\n};\n\n/**\n * Decorate a container's children: named attributes on each child's HOLDER and,\n * separately, on each child's `[data-blok-element-content]` wrapper.\n *\n * The single implementation behind the React, Vue and Angular per-child\n * decoration channels, so the three cannot drift on which element a hook lands\n * on or on when a dropped hook is cleaned up.\n *\n * BOTH levels exist because core's child-holder decoration law blesses both, and\n * a container needs both: the holder is the child's outer box (rails, indices,\n * hover states), while the content wrapper is where the child's own text box\n * begins — which is what a numbered rail or a connector line has to align to.\n * With only the holder reachable, a container had to encode core's wrapper chain\n * in its own CSS (`[data-step] > [data-blok-element-content] > …`) and broke\n * whenever that chain changed. Neither hook may introduce an element: holders\n * stay DIRECT children of the slot because core's reparenting and caret\n * sibling checks compare `holder.parentElement` by identity.\n *\n * Both are inert with respect to change tracking: core's mutation filter drops a\n * holder- or content-targeted attribute record for the CHILD block (both are\n * ancestors of the child's tool element, not descendants) and scores it\n * mutation-free for the CONTAINER (whose own `data-blok-mutation-free` host is\n * the nearest such ancestor).\n * @param ledger - the slot's ledgers from {@link createChildDecorationLedger}\n * @param children - the container's model children, in model order\n * @param decorators - the authored per-child decorators\n * @param decorators.childAttributes - written on each child's holder\n * @param decorators.childContentAttributes - written on each child's content wrapper\n */\nexport const applyChildDecoration = <Child extends DecoratableChild>(\n ledger: ChildDecorationLedger,\n children: Child[],\n decorators: {\n childAttributes?: ChildAttributesFn<Child>;\n childContentAttributes?: ChildAttributesFn<Child>;\n }\n): void => {\n applyPass(ledger.holders, children, decorators.childAttributes, holder => holder);\n applyPass(ledger.contents, children, decorators.childContentAttributes, contentWrapperOf);\n};\n","export type { BlockChildrenMountedPayload } from '@bloklabs/core';\n\n/**\n * Fired when a CONTAINER block's child holders have been mounted into its\n * child slot — the moment the child DOM has settled and a caret set into a\n * freshly inserted child sticks.\n *\n * Emitted by the React, Vue and Angular block adapters, whose portals commit a\n * frame AFTER core's `rendered()` hook; a vanilla container tool mounts its\n * children synchronously inside `rendered()`, so for those `block:rendered`\n * already means \"settled\". It fires on every reconciliation pass of the slot,\n * not only the first, so treat it as a settle signal rather than a change\n * signal.\n *\n * Public event name: `block:childrenMounted`.\n */\nexport const BlockChildrenMounted = 'block:childrenMounted';\n","import {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n Input,\n NgZone,\n Output,\n ViewChild,\n computed,\n effect,\n forwardRef,\n inject,\n signal,\n type AfterViewInit,\n type DoCheck,\n type OnDestroy,\n} from '@angular/core';\nimport { NG_VALUE_ACCESSOR, type ControlValueAccessor } from '@angular/forms';\nimport { BlokContentDirective, getConstructedCollaboration } from './blok-content.directive';\nimport { BLOK_DEFAULT_CONFIG } from './provide-blok';\nimport { createEmittedEchoWindow } from '../adapters-contract';\nimport { deepEqual } from '../adapters-contract';\nimport { equalsOutputData } from '../adapters-contract';\nimport { normalizeReadOnlyConfig } from '../adapters-contract';\nimport { toRenderableData } from '../adapters-contract';\nimport type {\n API,\n Blok,\n BlockMutationEvent,\n BlockRenderedPayload,\n BlocksRenderedPayload,\n BlokConfig,\n EditorWidth,\n LiveHandlers,\n LooseOutputData,\n OutputBlockData,\n OutputData,\n ResolvedTheme,\n ThemeMode,\n} from '@bloklabs/core';\nimport type { BlokAngularConfig } from './types';\n\n/**\n * Warning text for a controlled `data` change the adapter refuses to render\n * under collaboration. Kept verbatim in all three adapters (they share no code).\n * @param doc - the collaboration document id, for the reset endpoint in the text\n * @returns the message to warn with, once per adapter instance\n */\nconst collaborationDataIgnoredMessage = (doc?: string): string =>\n '[Blok] `data` is ignored while collaboration is on: the document lives on the sync service ' +\n 'and is shared with everyone editing it, so replacing it from this editor would overwrite their work. ' +\n `To replace the whole document, call POST /sync/${doc ?? '{doc}'}/reset on your server — ` +\n 'it reloads the document from your own document endpoint and every open editor picks it up. ' +\n 'To change part of it, use the blocks API (insert/update/delete).';\n\n/**\n * An EventEmitter that remembers its subscribed handlers. Core's final save on\n * destroy settles after Angular has unsubscribed the template listeners when a\n * tool saves asynchronously, so the component reads the handlers it saw at\n * destroy and calls them directly.\n */\nclass SaveEmitter<T> extends EventEmitter<T> {\n private readonly handlers = new Set<(value: T) => void>();\n\n override subscribe(observerOrNext?: unknown, error?: unknown, complete?: unknown): ReturnType<EventEmitter<T>['subscribe']> {\n const subscription = super.subscribe(observerOrNext, error, complete);\n const next = typeof observerOrNext === 'function'\n ? observerOrNext\n : (observerOrNext as { next?: unknown } | null | undefined)?.next;\n\n if (typeof next === 'function') {\n const handler = (value: T): void => {\n next.call(observerOrNext, value);\n };\n\n this.handlers.add(handler);\n subscription.add(() => this.handlers.delete(handler));\n }\n\n return subscription;\n }\n\n liveHandlers(): Array<(value: T) => void> {\n return [...this.handlers];\n }\n}\n\n/**\n * The blessed all-in-one Angular component for embedding Blok (mirrors React's\n * `BlokEditor`). Delegates instance lifecycle to an internal `BlokContentDirective`\n * and layers the typed reactive input/output API on top.\n *\n * Reactive inputs (`readOnly`, `hideToolbar`, `toolbarPosition`,\n * `inlineToolbar`, `theme`, `width`, `placeholder`, `autofocus`, `styleTokens`,\n * `i18n`, `data`) are synced in place after mount via effects — `hideToolbar`\n * through `editor.toolbar.setHidden()`, `toolbarPosition` through\n * `editor.toolbar.setPosition()`, `inlineToolbar` through\n * `editor.tools.setInlineToolbar()` (content-compared),\n * `styleTokens` through `editor.tokens.set()` (replace semantics),\n * `i18n` through `editor.i18n.update()` (deep-equal–deduped; seeded at\n * construction so the locale resolves during boot) and `data`\n * through `editor.render()` (content-deduped via `equalsOutputData`); everything\n * else seeds construction.\n *\n * Implementation note: classic `@Input()`/`@ViewChild()` decorators are used\n * (not signal `input()`/`viewChild()`) for JIT compatibility — see\n * `BlokContentDirective`. Each reactive input is backed by an internal `signal`\n * so effect-based syncing still works; the public template API is unchanged.\n */\n@Component({\n selector: 'blok-editor',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n exportAs: 'blok',\n imports: [BlokContentDirective],\n template: `<div blokContent [config]=\"buildConfig()\" [recreateKey]=\"recreateKey\"></div>`,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => BlokEditorComponent),\n multi: true,\n },\n ],\n})\nexport class BlokEditorComponent implements AfterViewInit, DoCheck, OnDestroy, ControlValueAccessor {\n private readonly ngZone = inject(NgZone);\n /** App-wide defaults from `provideBlok()`; merged UNDER per-instance inputs. */\n private readonly defaults = inject(BLOK_DEFAULT_CONFIG, { optional: true }) ?? {};\n\n @ViewChild(BlokContentDirective) private contentQuery?: BlokContentDirective;\n /** Signal bridge for the @ViewChild directive so effects react to its arrival. */\n private readonly content = signal<BlokContentDirective | null>(null);\n\n /**\n * Output half of two-way `[(data)]`. Emits the editor's serialized content on\n * every change. Wiring the core `onSave` callback is gated on this being\n * observed, since its mere presence makes the core serialize on every batch.\n */\n /** Emits the live Blok instance once ready, after `instance()` is populated. */\n @Output() readonly ready = new EventEmitter<Blok>();\n\n @Output() readonly dataChange: EventEmitter<OutputData> = new SaveEmitter<OutputData>();\n\n /** Fires with the full serialized content on every change (notification half). */\n @Output() readonly save: EventEmitter<OutputData> = new SaveEmitter<OutputData>();\n\n /** Raw block mutation channel (core `onChange`). */\n @Output() readonly change = new EventEmitter<{\n api: API;\n event: BlockMutationEvent | BlockMutationEvent[];\n }>();\n\n /** Fires after the editor finishes (re-)rendering (core `onAfterRender`). */\n @Output() readonly afterRender = new EventEmitter<API>();\n\n /** Fires with the resolved theme whenever it changes (core `onThemeChange`). */\n @Output() readonly themeChange = new EventEmitter<ResolvedTheme>();\n\n /** Fires after a batch render completes (core `blocks:rendered` event). */\n @Output() readonly blocksRendered = new EventEmitter<BlocksRenderedPayload>();\n\n /** Fires for each block rendered into the DOM (core `block:rendered` event). */\n @Output() readonly blockRendered = new EventEmitter<BlockRenderedPayload>();\n\n /**\n * Transform hook applied to blocks before render (core `onBeforeRender`). Must\n * return the (possibly modified) block list. An input, not an output, because\n * it returns a value.\n */\n @Input() onBeforeRender?: (blocks: OutputBlockData[]) => OutputBlockData[];\n\n /**\n * Transform hook applied to pasted HTML (core `onBeforePaste`). Returns the\n * (possibly modified) html, or null to drop the paste.\n */\n @Input() onBeforePaste?: (html: string) => string | null;\n\n /**\n * Error channel (core `onError`). Fires with the raised error whenever an\n * editor operation — currently serialization — fails instead of only logging.\n */\n @Input() onError?: BlokConfig['onError'];\n\n /**\n * Failed-image channel (core `onImageFailure`). Return false to replace blok's own notice.\n */\n @Input() onImageFailure?: BlokConfig['onImageFailure'];\n\n // ---- Reactive inputs (signal-backed setters; synced in place, never recreate) ----\n // Default undefined (not false) so an unset input falls back to a provideBlok\n // default; the readOnly effect / buildConfig coerce undefined to false.\n // Accepts the object form (`{ hideControls }`) too — it flows through\n // buildConfig unchanged and the effect expands it to\n // `readOnly.set(enabled, { hideControls })`.\n private readonly readOnly$ = signal<BlokConfig['readOnly'] | undefined>(undefined);\n @Input() set readOnly(value: BlokConfig['readOnly'] | undefined) {\n this.readOnly$.set(value);\n }\n\n private readonly hideToolbar$ = signal<boolean | undefined>(undefined);\n @Input() set hideToolbar(value: boolean | undefined) {\n this.hideToolbar$.set(value);\n }\n\n private readonly toolbarPosition$ = signal<BlokConfig['toolbarPosition'] | undefined>(undefined);\n @Input() set toolbarPosition(value: BlokConfig['toolbarPosition'] | undefined) {\n this.toolbarPosition$.set(value);\n }\n\n private readonly inlineToolbar$ = signal<boolean | string[] | undefined>(undefined);\n @Input() set inlineToolbar(value: boolean | string[] | undefined) {\n this.inlineToolbar$.set(value);\n }\n\n private readonly theme$ = signal<ThemeMode | undefined>(undefined);\n @Input() set theme(value: ThemeMode | undefined) {\n this.theme$.set(value);\n }\n\n private readonly width$ = signal<EditorWidth | undefined>(undefined);\n @Input() set width(value: EditorWidth | undefined) {\n this.width$.set(value);\n }\n\n private readonly placeholder$ = signal<string | false | undefined>(undefined);\n @Input() set placeholder(value: string | false | undefined) {\n this.placeholder$.set(value);\n }\n\n /**\n * Theme tokens. Construction-only config forced hosts with a live light/dark\n * toggle to recreate the editor or hand-write the global stylesheet Blok\n * already injects; this drives the runtime `tokens` API instead.\n */\n private readonly styleTokens$ = signal<Record<string, string> | undefined>(undefined);\n @Input() set styleTokens(value: Record<string, string> | undefined) {\n this.styleTokens$.set(value);\n }\n\n /**\n * Locale, host message overrides and text direction. `config.i18n` was\n * consumed once at boot, so a host driving a language switcher had to\n * recreate the editor (losing caret, focus and undo stack) to relabel the\n * UI; this drives the runtime `i18n.update` API instead. `defaultLocale` is\n * not forwarded — it only affects the INITIAL locale resolution.\n */\n private readonly i18n$ = signal<BlokConfig['i18n'] | undefined>(undefined);\n @Input() set i18n(value: BlokConfig['i18n'] | undefined) {\n this.i18n$.set(value);\n }\n\n private readonly autofocus$ = signal<boolean | undefined>(false);\n @Input() set autofocus(value: boolean | undefined) {\n this.autofocus$.set(value);\n }\n\n // ---- Reactive content (seeds construction, then re-renders on change) ----\n private readonly data$ = signal<OutputData | LooseOutputData | null | undefined>(undefined);\n @Input() set data(value: OutputData | LooseOutputData | null | undefined) {\n this.data$.set(value);\n }\n\n // ---- Construction-only seed inputs (read once at construction) ----\n @Input() tools?: BlokConfig['tools'];\n /** Host-supplied per-type block migrations applied at load (merged across layers). */\n @Input() migrations?: BlokConfig['migrations'];\n\n /**\n * Escape hatch: a full config object for keys without a dedicated input\n * (sanitizer, minHeight, …). Layered between provideBlok\n * defaults and the discrete inputs.\n */\n @Input() config?: Partial<BlokAngularConfig>;\n\n /** Changing this input's identity destroys and recreates the editor (≙ React `deps`). */\n @Input() recreateKey: unknown;\n\n /**\n * Content the editor currently reflects. Set when seeded, when the data effect\n * renders, when the editor emits its own output (`coreOnSave`) and when the\n * imperative `render()` facade lands. A controlled `data` echo that\n * content-equals this baseline is a no-op, so it won't clobber the caret.\n * Renders are serialized via `renderChain`. `undefined` means \"nothing recorded\n * yet\" — never an empty document.\n */\n private lastRenderedData?: OutputData | LooseOutputData | null;\n /**\n * Content of the render currently queued or in flight — distinct from\n * `lastRenderedData`, which names the last SUCCESSFUL one. The data effect\n * dedupes against both, so an echo arriving mid-render is suppressed without\n * the baseline having to move before the render resolves (a failed render\n * would then strand it on content the editor never showed, and the host's\n * retry of that same content would be deduped away forever).\n * `undefined` means \"nothing in flight\".\n */\n private pendingData?: OutputData | LooseOutputData | null;\n /**\n * Window of recently emitted `onSave` payloads. `lastRenderedData` remembers\n * only the LAST one, but a host that persists on save and refetches can echo\n * an EARLIER save back after a newer one already replaced the baseline (the\n * user kept typing). That stale echo is still the editor's own output, and\n * rendering it is a whole-document replace — it would drop every character\n * typed between the two saves and hand the rewound document to the next save,\n * making the loss permanent in the host's store. Every `[data]` path funnels\n * through the `data$` signal (the template input AND `writeValue`), so the one\n * check in the data effect covers `patchValue` / `setValue` / `reset` too.\n */\n private readonly emittedEcho = createEmittedEchoWindow();\n\n /** Last token set pushed through `tokens.set`, for deep-equal deduping. */\n private appliedTokens?: Record<string, string>;\n /** Last i18n config pushed through `i18n.update`, for deep-equal deduping. */\n private appliedI18n?: BlokConfig['i18n'];\n /** Editor instance the i18n baseline above belongs to. */\n private i18nAppliedFor: Blok | null = null;\n /** Last value pushed through `tools.setInlineToolbar`, for content-compare deduping. */\n private appliedInlineToolbar?: boolean | string[];\n private seededEditor: Blok | null = null;\n private renderChain: Promise<void> = Promise.resolve();\n /**\n * Editor the single collaboration warning has already been emitted for. Keyed\n * by the editor, not a boolean, so the editor a `recreateKey` bump creates\n * warns on its own first ignored `data` change instead of inheriting the\n * previous editor's \"already warned\" flag and going silent.\n */\n private collaborationWarnedFor: Blok | null = null;\n\n /** Registered by `ControlValueAccessor.registerOnChange` (Angular forms). */\n private cvaOnChange?: (data: OutputData) => void;\n private cvaOnTouched?: () => void;\n\n /**\n * Core `onSave` wrapper. Records the editor's own serialized output as the\n * rendered baseline BEFORE notifying Angular, so a controlled consumer echoing\n * it straight back into `data` deep-equals the baseline and is deduped to a\n * no-op (no redundant render, no caret reset). Re-enters the Angular zone since\n * the editor runs outside it.\n *\n * Falls back to an escape-hatch `[config]` callback when nothing Angular-side\n * consumes the save — the baseline is recorded either way, so the controlled\n * `data` dedupe works on both paths.\n */\n private readonly coreOnSave = (data: OutputData, api: API): void => {\n this.lastRenderedData = data;\n this.emittedEcho.record(data);\n\n const handlersAtDestroy = this.saveHandlersAtDestroy;\n\n if (handlersAtDestroy.length > 0) {\n this.ngZone.run(() => handlersAtDestroy.forEach((handler) => handler(data)));\n\n return;\n }\n\n if (this.hasSaveConsumer()) {\n this.ngZone.run(() => {\n this.dataChange.emit(data);\n this.save.emit(data);\n this.cvaOnChange?.(data);\n this.cvaOnTouched?.();\n });\n\n return;\n }\n\n this.escapeHatchConfig().onSave?.(data, api);\n };\n\n /**\n * Stable wrappers for the remaining live callbacks. Each resolves its target\n * at call time (an observed output, else the `[config]` escape hatch), so a\n * pushed handler never goes stale and only PRESENCE has to be synced.\n */\n private readonly coreOnChange = (\n api: API,\n event: BlockMutationEvent | BlockMutationEvent[]\n ): void => {\n if (this.change.observed) {\n this.ngZone.run(() => this.change.emit({ api, event }));\n\n return;\n }\n\n this.escapeHatchConfig().onChange?.(api, event);\n };\n\n private readonly coreOnAfterRender = (api: API): void => {\n if (this.afterRender.observed) {\n this.ngZone.run(() => this.afterRender.emit(api));\n\n return;\n }\n\n this.escapeHatchConfig().onAfterRender?.(api);\n };\n\n /*\n * Transforms run synchronously inside core's render pipeline and must return a\n * value — never wrap them in ngZone.run.\n */\n private readonly coreOnBeforeRender = (blocks: OutputBlockData[]): OutputBlockData[] => {\n const transform = this.onBeforeRender ?? this.escapeHatchConfig().onBeforeRender;\n\n return transform?.(blocks) ?? blocks;\n };\n\n private readonly coreOnEnter = (event: KeyboardEvent, api: API): boolean | void =>\n this.escapeHatchConfig().onEnter?.(event, api);\n\n private readonly coreOnSubmit = (data: OutputData, api: API): void => {\n this.escapeHatchConfig().onSubmit?.(data, api);\n };\n\n /** provideBlok defaults merged under the `[config]` escape hatch. */\n private escapeHatchConfig(): Partial<BlokAngularConfig> {\n return { ...this.defaults, ...this.config };\n }\n\n /** True when an output, a two-way binding or Angular forms consumes `onSave`. */\n private hasSaveConsumer(): boolean {\n return this.dataChange.observed || this.save.observed || this.cvaOnChange !== undefined;\n }\n\n /**\n * The live callbacks this component currently wires into core, keyed by\n * handler name — `undefined` for the ones nothing consumes.\n *\n * PRESENCE is the semantics in core (an `onSubmit` turns Enter into\n * serialize-and-submit, an `onSave` arms the change-observation pipeline), so\n * an unconsumed callback must stay absent. One source of truth for both the\n * construction config and the runtime sync in `ngDoCheck`, so the two cannot\n * drift.\n * @returns the wrappers to install, `undefined` where nothing is wired\n */\n private liveHandlers(): LiveHandlers {\n const cfg = this.escapeHatchConfig();\n\n return {\n onChange: this.change.observed || cfg.onChange !== undefined ? this.coreOnChange : undefined,\n onSave: this.hasSaveConsumer() || cfg.onSave !== undefined ? this.coreOnSave : undefined,\n onEnter: cfg.onEnter !== undefined ? this.coreOnEnter : undefined,\n onSubmit: cfg.onSubmit !== undefined ? this.coreOnSubmit : undefined,\n onBeforeRender:\n this.onBeforeRender !== undefined || cfg.onBeforeRender !== undefined\n ? this.coreOnBeforeRender\n : undefined,\n onAfterRender:\n this.afterRender.observed || cfg.onAfterRender !== undefined\n ? this.coreOnAfterRender\n : undefined,\n };\n }\n\n /** Handler presence installed on the live editor (the sync dedupe baseline). */\n private appliedHandlers: LiveHandlers = {};\n\n /** Live Blok instance, or null until `isReady` resolves / after destroy. */\n readonly instance = computed<Blok | null>(() => this.content()?.instance() ?? null);\n\n /** Guards `ready` to one emission per editor instance. */\n private lastReadyInstance: Blok | null = null;\n\n /**\n * Construction config handed to the directive. Seeds the editor's initial\n * values; the directive only reads it once (at construction), so post-mount\n * changes to construction-only inputs are no-ops by design.\n */\n buildConfig(): Partial<BlokAngularConfig> {\n // Precedence: provideBlok defaults < [config] escape hatch < discrete inputs.\n const cfg: Partial<BlokAngularConfig> = { ...this.defaults, ...this.config };\n\n // The object form ({ hideControls }) is preserved as-is; the readOnly\n // effect expands it into `readOnly.set(enabled, { hideControls })`.\n cfg.readOnly = this.readOnly$() ?? this.config?.readOnly ?? this.defaults.readOnly ?? false;\n\n const hideToolbar = this.hideToolbar$();\n\n if (hideToolbar !== undefined) {\n cfg.hideToolbar = hideToolbar;\n }\n\n const toolbarPosition = this.toolbarPosition$();\n\n if (toolbarPosition !== undefined) {\n cfg.toolbarPosition = toolbarPosition;\n }\n\n const inlineToolbar = this.inlineToolbar$();\n\n if (inlineToolbar !== undefined) {\n cfg.inlineToolbar = inlineToolbar;\n }\n\n // tools registries are MERGED (not replaced) across all three layers so a\n // shared registry composes with per-instance additions.\n if (\n this.tools !== undefined ||\n this.config?.tools !== undefined ||\n this.defaults.tools !== undefined\n ) {\n cfg.tools = { ...this.defaults.tools, ...this.config?.tools, ...this.tools };\n }\n\n // migration registries merge like tools: shared defaults compose with\n // per-instance rules.\n if (\n this.migrations !== undefined ||\n this.config?.migrations !== undefined ||\n this.defaults.migrations !== undefined\n ) {\n cfg.migrations = { ...this.defaults.migrations, ...this.config?.migrations, ...this.migrations };\n }\n\n const data = this.data$();\n\n if (data !== undefined) {\n cfg.data = data;\n }\n\n const theme = this.theme$();\n\n if (theme !== undefined) {\n cfg.theme = theme;\n }\n\n const width = this.width$();\n\n if (width !== undefined) {\n cfg.width = width;\n }\n\n const placeholder = this.placeholder$();\n\n if (placeholder !== undefined) {\n cfg.placeholder = placeholder;\n }\n\n // Seeded at construction (not applied by the i18n effect) so the locale is\n // resolved during boot instead of flashing the default language first.\n const i18n = this.i18n$();\n\n if (i18n !== undefined) {\n cfg.i18n = i18n;\n }\n\n // Opt-in: only attach each live callback when the consumer actually consumes\n // it (an observed output, a registered forms hook, a provided transform or an\n // escape-hatch config callback). Their mere presence makes the core serialize\n // / run hooks on every change. The same map drives the runtime sync in\n // `ngDoCheck`, so construction and post-mount can never disagree.\n const handlers = this.liveHandlers();\n\n cfg.onChange = handlers.onChange;\n cfg.onSave = handlers.onSave;\n cfg.onEnter = handlers.onEnter;\n cfg.onSubmit = handlers.onSubmit;\n cfg.onBeforeRender = handlers.onBeforeRender;\n cfg.onAfterRender = handlers.onAfterRender;\n\n this.appliedHandlers = handlers;\n\n if (this.themeChange.observed) {\n cfg.onThemeChange = (resolved: ResolvedTheme): void =>\n this.ngZone.run(() => this.themeChange.emit(resolved));\n }\n\n // Transforms run synchronously inside core's paste pipeline and must return a\n // value — never wrap them in ngZone.run.\n const beforePaste = this.onBeforePaste;\n\n if (beforePaste !== undefined) {\n cfg.onBeforePaste = (html: string): string | null => beforePaste(html);\n }\n\n const onError = this.onError;\n\n if (onError !== undefined) {\n cfg.onError = onError;\n }\n\n const onImageFailure = this.onImageFailure;\n\n if (onImageFailure !== undefined) {\n cfg.onImageFailure = onImageFailure;\n }\n\n return cfg;\n }\n\n ngAfterViewInit(): void {\n this.content.set(this.contentQuery ?? null);\n }\n\n /** Save consumers captured at destroy, for core's final save. */\n private saveHandlersAtDestroy: Array<(data: OutputData) => void> = [];\n\n // Runs before Angular unsubscribes the host's output listeners and before\n // the forms directive swaps the registered CVA callbacks for noops.\n ngOnDestroy(): void {\n const { cvaOnChange, cvaOnTouched } = this;\n const forms = cvaOnChange === undefined\n ? []\n : [(data: OutputData): void => {\n cvaOnChange(data);\n cvaOnTouched?.();\n }];\n\n this.saveHandlersAtDestroy = [\n ...[this.dataChange, this.save].flatMap((emitter) =>\n emitter instanceof SaveEmitter ? emitter.liveHandlers() : []\n ),\n ...forms,\n ];\n }\n\n /**\n * Reactive callback presence.\n *\n * Callback wiring was decided once, at construction, and in core the presence\n * of a handler IS the semantics: an `onSubmit` makes Enter serialize-and-submit\n * instead of splitting the block, an `onSave` arms the whole change-observation\n * pipeline. A `[config]` swap, an `*ngIf`-gated `(save)` output or a\n * `registerOnChange` from Angular forms arriving after mount therefore needed a\n * `recreateKey` bump — destroying the editor and losing caret and undo history.\n *\n * Diff the wired handlers against what is installed and push genuine flips\n * through the runtime `handlers.set` API, writing `undefined` for a handler\n * that lost its consumer so the change stays reversible. `ngDoCheck` (not an\n * `effect`) because `EventEmitter.observed` and the plain `@Input` transforms\n * are not signals; the comparison is six identity checks against stable\n * wrappers, so an unchanged cycle pushes nothing.\n */\n ngDoCheck(): void {\n const editor = this.instance();\n\n if (editor === null) {\n return;\n }\n\n const desired = this.liveHandlers();\n const applied = this.appliedHandlers;\n const diff: LiveHandlers = {};\n const changed: { value: boolean } = { value: false };\n\n const sync = <K extends keyof LiveHandlers>(key: K, write: (value: LiveHandlers[K]) => void): void => {\n if (desired[key] === applied[key]) {\n return;\n }\n\n applied[key] = desired[key];\n changed.value = true;\n write(desired[key]);\n };\n\n sync('onChange', (value) => {\n diff.onChange = value;\n });\n sync('onSave', (value) => {\n diff.onSave = value;\n });\n sync('onEnter', (value) => {\n diff.onEnter = value;\n });\n sync('onSubmit', (value) => {\n diff.onSubmit = value;\n });\n sync('onBeforeRender', (value) => {\n diff.onBeforeRender = value;\n });\n sync('onAfterRender', (value) => {\n diff.onAfterRender = value;\n });\n\n if (changed.value) {\n editor.handlers.set(diff);\n }\n }\n\n // ---- Curated imperative facade (delegates to the live instance; no-ops until ready) ----\n\n /** Serialize the current content. Resolves undefined until the editor is ready. */\n save$(): Promise<OutputData> | undefined {\n return this.instance()?.save();\n }\n\n /** Ask before an in-app navigation (see `Blok.confirmLeave`). Resolves true until the editor is ready. */\n confirmLeave(): Promise<boolean> {\n return this.instance()?.confirmLeave() ?? Promise.resolve(true);\n }\n\n /** Move the caret into the editor. */\n focus(atEnd?: boolean): void {\n this.instance()?.focus(atEnd);\n }\n\n /**\n * Replace the editor content. Resolves undefined until the editor is ready.\n *\n * Safe to mix with a controlled `[data]` input: the rendered document becomes\n * the content baseline once the call lands, so a later `[data]` change back to\n * the previous document still re-renders instead of being deduped against a\n * baseline the editor no longer reflects. Recorded only on the resolved path —\n * a failed render leaves the editor on its previous content.\n * @param data - the document to render\n */\n render(data: OutputData | LooseOutputData): Promise<void> | undefined {\n const editor = this.instance();\n\n if (editor === null) {\n return undefined;\n }\n\n return editor.render(data).then(() => {\n this.lastRenderedData = data;\n // Out-of-band content: nothing the reactive effect queued describes the\n // editor any more, and neither does anything it emitted earlier — a later\n // `[data]` set back to one of those payloads must render, not be dismissed\n // as an echo.\n this.pendingData = undefined;\n this.emittedEcho.clear();\n });\n }\n\n constructor() {\n // Each effect reads `instance()` so it re-applies once the editor appears\n // (the Angular analog of React's `editor` effect-dependency).\n effect(() => {\n const editor = this.instance();\n const readOnly = this.readOnly$() ?? this.config?.readOnly;\n\n if (editor) {\n const { enabled, hideControls } = normalizeReadOnlyConfig(readOnly);\n\n // Only the object form carries options; the boolean form keeps the\n // one-argument call so it never clobbers a config-seeded hideControls.\n if (typeof readOnly === 'object' && readOnly !== null) {\n void editor.readOnly.set(enabled, { hideControls });\n } else {\n void editor.readOnly.set(enabled);\n }\n }\n });\n\n effect(() => {\n const editor = this.instance();\n const hideToolbar = this.hideToolbar$();\n\n if (editor && hideToolbar !== undefined) {\n editor.toolbar.setHidden(hideToolbar);\n }\n });\n\n effect(() => {\n const editor = this.instance();\n const toolbarPosition = this.toolbarPosition$();\n\n if (editor && toolbarPosition !== undefined) {\n editor.toolbar.setPosition(toolbarPosition);\n }\n });\n\n // Content-compared (not identity): a new array with the same tool names is\n // a no-op, so template-inline array literals don't thrash the assignment.\n effect(() => {\n const editor = this.instance();\n const inlineToolbar = this.inlineToolbar$();\n\n if (\n !editor ||\n inlineToolbar === undefined ||\n deepEqual(inlineToolbar, this.appliedInlineToolbar)\n ) {\n return;\n }\n\n this.appliedInlineToolbar = Array.isArray(inlineToolbar) ? [...inlineToolbar] : inlineToolbar;\n editor.tools.setInlineToolbar(inlineToolbar);\n });\n\n effect(() => {\n const editor = this.instance();\n const theme = this.theme$();\n\n if (editor && theme !== undefined) {\n editor.theme.set(theme);\n }\n });\n\n effect(() => {\n const editor = this.instance();\n const width = this.width$();\n\n if (editor && width !== undefined) {\n editor.width.set(width);\n }\n });\n\n effect(() => {\n const editor = this.instance();\n const placeholder = this.placeholder$();\n\n if (editor && placeholder !== undefined) {\n editor.placeholder.set(placeholder);\n }\n });\n\n effect(() => {\n const editor = this.instance();\n const tokens = this.styleTokens$() ?? this.config?.style?.tokens;\n\n if (!editor || tokens === undefined || deepEqual(tokens, this.appliedTokens)) {\n return;\n }\n\n this.appliedTokens = { ...tokens };\n editor.tokens.set(tokens);\n });\n\n effect(() => {\n const editor = this.instance();\n const i18n = this.i18n$() ?? this.config?.i18n;\n\n if (!editor) {\n return;\n }\n\n /*\n * A freshly constructed editor already resolved this config during its\n * own boot (buildConfig seeds it), so record the baseline and push\n * nothing — re-applying it here would reload the locale after mount and\n * flash the default language.\n */\n if (this.i18nAppliedFor !== editor) {\n this.i18nAppliedFor = editor;\n this.appliedI18n = i18n === undefined ? undefined : { ...i18n };\n\n return;\n }\n\n const previous = this.appliedI18n;\n\n if ((i18n === undefined && previous?.direction === undefined) || deepEqual(i18n, previous)) {\n return;\n }\n\n this.appliedI18n = i18n === undefined ? undefined : { ...i18n };\n\n const { locale, messages, direction } = i18n ?? {};\n // A dropped direction must be cleared, or the editor keeps the old one.\n const nextDirection = direction ?? (previous?.direction === undefined ? undefined : null);\n\n void editor.i18n.update({\n ...(locale === undefined ? {} : { locale }),\n ...(messages === undefined ? {} : { messages }),\n ...(nextDirection === undefined ? {} : { direction: nextDirection }),\n });\n });\n\n effect(() => {\n const editor = this.instance();\n\n if (editor && this.autofocus$()) {\n editor.focus();\n }\n });\n\n // Reactive content. `data` seeds the editor at construction; afterwards a new\n // *content* value re-renders via the public render() API (deep-equal-deduped\n // and serialized, so an unchanged reference — including the editor's own\n // echoed output — is a no-op and never clobbers the caret).\n effect(() => {\n const editor = this.instance();\n const data = this.data$();\n\n if (!editor || data === undefined) {\n return;\n }\n\n // A freshly created editor was already seeded with `data` at construction;\n // record it without re-rendering.\n if (this.seededEditor !== editor) {\n this.seededEditor = editor;\n this.lastRenderedData = data;\n // A render still pending on a PRIOR editor is moot for this fresh one;\n // clear it so its content cannot dedupe a needed render here.\n this.pendingData = undefined;\n // Payloads emitted by a PRIOR editor are likewise moot for this one.\n this.emittedEcho.clear();\n\n return;\n }\n\n // Structural comparison (`equalsOutputData`, not a raw deep-equal): a host\n // that persists the editor's own document and hands back a stripped copy —\n // fresh `time`, dropped ids, no `lastEditedAt` stamp — is still echoing\n // content the editor already shows, and re-rendering it would reset the\n // caret for zero visual change. `undefined` means \"nothing recorded yet\",\n // which is NOT an empty document, so it must never match.\n const baseline = this.lastRenderedData;\n\n if (baseline !== undefined && equalsOutputData(data, baseline)) {\n return;\n }\n\n // Same content already queued or in flight: re-rendering it would reset\n // the caret for zero visual change.\n if (this.pendingData !== undefined && equalsOutputData(data, this.pendingData)) {\n return;\n }\n\n // Skip stale echoes: content the editor itself emitted via `onSave`\n // recently, arriving back reshaped (fresh envelope, stripped ids) and/or\n // late — after a newer save already replaced the baseline above. Checked\n // WITHOUT touching `pendingData`, so an echo landing mid-render still\n // leaves that render owning its own in-flight marker.\n if (this.emittedEcho.matches(data)) {\n return;\n }\n\n // Under collaboration the document belongs to the sync service, and\n // render() refuses a wholesale replace — so don't attempt one. The input's\n // premise (\"this value IS the document\") does not hold here. Read from\n // what the DIRECTIVE built this very editor with, never from the current\n // `[config]`: `collaboration` is mount-fixed, so a host that rebuilds the\n // config without the key (a template literal recomputed by change\n // detection, an async config signal landing) is still driving a live\n // collaboration session and deserves the warning rather than a silently\n // rejected render.\n const collaboration = getConstructedCollaboration(editor);\n\n if (collaboration !== undefined) {\n if (this.collaborationWarnedFor !== editor) {\n this.collaborationWarnedFor = editor;\n console.warn(collaborationDataIgnoredMessage(collaboration.doc));\n }\n\n return;\n }\n\n // Genuinely external content takes over: earlier emitted payloads are\n // moot, and keeping them could wrongly no-op a later deliberate revert to\n // one of them.\n this.emittedEcho.clear();\n\n // Marked in flight, but the SUCCESS baseline does not move until the\n // render actually lands — a failed render leaves the editor on its previous\n // content, so claiming otherwise would dedupe away the host's retry.\n this.pendingData = data;\n // `data` may be null (a controlled \"clear to empty\"); render() throws on\n // null, so normalize null → { blocks: [] } at the boundary.\n // The rejection handler OWNS a failed render: without it the rejection sits\n // in `renderChain` with no handler until the next `data` change attaches\n // one, which the runtime reports as an unhandled rejection. Swallowing it\n // here also leaves the chain resolved, so the next queued render still runs.\n this.renderChain = this.renderChain\n .then(() => editor.render(toRenderableData(data)))\n .then(\n () => {\n this.lastRenderedData = data;\n },\n () => undefined\n )\n .then(() => {\n // Clear the in-flight marker unless a newer render has claimed it —\n // that newer one owns the clear.\n if (this.pendingData === data) {\n this.pendingData = undefined;\n }\n });\n });\n\n // Emit `ready` once per editor, after `instance()` is populated so a consumer\n // reading the component/ref instance inside the handler sees it.\n effect(() => {\n const editor = this.instance();\n\n if (editor && editor !== this.lastReadyInstance) {\n this.lastReadyInstance = editor;\n this.ready.emit(editor);\n }\n });\n\n // Subscribe to the editor's rendered-lifecycle events once it exists (gated on\n // the outputs being observed). `onCleanup` unsubscribes when the instance is\n // replaced or the component is destroyed.\n effect((onCleanup) => {\n const editor = this.instance();\n\n if (!editor) {\n return;\n }\n\n const handlers: Array<[string, (payload?: unknown) => void]> = [];\n\n if (this.blocksRendered.observed) {\n const handler = (payload?: unknown): void =>\n this.ngZone.run(() => this.blocksRendered.emit(payload as BlocksRenderedPayload));\n\n editor.on('blocks:rendered', handler);\n handlers.push(['blocks:rendered', handler]);\n }\n\n if (this.blockRendered.observed) {\n const handler = (payload?: unknown): void =>\n this.ngZone.run(() => this.blockRendered.emit(payload as BlockRenderedPayload));\n\n editor.on('block:rendered', handler);\n handlers.push(['block:rendered', handler]);\n }\n\n onCleanup(() => {\n for (const [name, handler] of handlers) {\n editor.off(name, handler);\n }\n });\n });\n }\n\n // ---- ControlValueAccessor (optional forms integration) ----\n\n /** Seeds/renders an externally-set form value through the same dedup machinery. */\n writeValue(value: OutputData | LooseOutputData | null): void {\n this.data$.set(value ?? undefined);\n }\n\n registerOnChange(fn: (data: OutputData) => void): void {\n this.cvaOnChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.cvaOnTouched = fn;\n }\n\n /** Form disabled state maps to the editor's read-only mode (via the readOnly effect). */\n setDisabledState(isDisabled: boolean): void {\n this.readOnly$.set(isDisabled);\n }\n}\n","import type { API, BlockAPI, BlockOrigin, BlockToolConstructable, BlockToolConstructorOptions, BlockToolData, ToolboxConfig } from '@bloklabs/core';\n// packages/angular/src/createAngularBlock.ts\nimport { signal, type Type, type WritableSignal } from '@angular/core';\n\nimport {\n applyChildDecoration,\n BlockChildrenMounted,\n createChildDecorationLedger,\n DATA_ATTR,\n} from '../adapters-contract';\nimport { deepEqual } from '../adapters-contract';\nimport { fillDefaults, type PropSchema } from '../adapters-contract';\nimport { mountChildBlocks, withSlotlessDescendants } from '../adapters-contract';\n\nimport type { AngularBlockRenderContext, ChildAttributesFn } from './block-context';\nimport { BLOK_PORTAL_REGISTRY_CONFIG_KEY, type BlockPortalRegistry } from './block-portal-registry';\n\n/**\n * Every STATIC member of core's block-tool contract an Angular block may declare\n * for itself — `ownsChildren`, `keepsChildrenOnEnter`, `conversionConfig`,\n * `pasteConfig`, `sanitize`, `shortcut`, `upgradeData`, and whatever core adds\n * next. Derived from\n * `BlockToolConstructable` rather than enumerated, so a new core static needs no\n * adapter change to become reachable.\n *\n * `toolbox` and `isReadOnlySupported` are excluded because the factory owns\n * them: `toolbox` is authored as {@link CreateAngularBlockSpec.toolbox}, and\n * in-place read-only support is unconditional.\n */\nexport type BlockToolStatics = Omit<BlockToolConstructable, 'toolbox' | 'isReadOnlySupported'>;\n\n/** Statics the generated class owns; an authored `statics` bag can never take them over. */\nconst RESERVED_STATICS: readonly string[] = ['toolbox', 'isReadOnlySupported', '__isBlokAngularBlock'];\n\n/**\n * Origins that mean \"the author just made this block\" — the only ones that fire\n * {@link CreateAngularBlockSpec.onCreated}. Written as an allow-list so a future\n * core origin fails CLOSED (no creation signal) instead of silently opting in.\n *\n * `undefined` is included because core always supplies an origin: an absent one\n * means a host hand-built the constructor options, which is an explicit\n * creation — the same reading core's own container tools apply.\n *\n * Note what is NOT the axis here: `origin === 'user'`. A container gated on that\n * alone would refuse to seed for `api.blocks.insert('steps')` and for a\n * turn-into, leaving an empty, unusable container.\n */\nconst CREATION_ORIGINS: ReadonlySet<BlockOrigin | undefined> = new Set<BlockOrigin | undefined>([\n undefined,\n 'user',\n 'api',\n 'convert',\n]);\n\n/**\n * Announce that a container's child holders have settled in its slot — the\n * signal a host waits on before putting the caret into a freshly inserted\n * child.\n *\n * Optional-chained: the editor always supplies `events`, but a host unit test\n * may hand a block a partial `api`, and an observability signal must never be\n * able to break a render.\n * @param api - the editor-level API\n * @param blockId - the container block's id\n * @param children - the container's model children, in model order\n */\nconst emitChildrenMounted = (api: API, blockId: string, children: BlockAPI[]): void => {\n api?.events?.emit(BlockChildrenMounted, {\n blockId,\n childIds: children.map(child => child.id),\n });\n};\n\n/**\n * Second argument of {@link CreateAngularBlockSpec.onMounted} and\n * {@link CreateAngularBlockSpec.onCreated} — everything the block cannot read\n * off its own `BlockAPI`.\n */\nexport interface AngularBlockMountedContext {\n /**\n * Why this block instance was constructed: a CREATION origin (`user`, `api`,\n * `convert`) means the author just made it, so seeding default children is\n * correct; a RESTORE origin (`load`, `replay`, `paste`) means the document\n * already says what the children are. `probe` is an off-tree instance built\n * only to read a tool's default data — it must not touch the block tree at\n * all. Defaults to `'api'` when the constructor was handed no origin.\n */\n origin: BlockOrigin;\n /** The editor-level API (`api.blocks`, `api.caret`, `api.events`…). */\n api: API;\n}\n\n/** Spec for {@link createAngularBlock}. Authored as a standalone component. */\nexport interface CreateAngularBlockSpec<Data = BlockToolData> {\n /** Tool type name (registered key). */\n type: string;\n /** Optional toolbox entry. */\n toolbox?: ToolboxConfig;\n /** Declarative defaults that also define the exact `save()` key set. */\n propSchema: PropSchema;\n /**\n * The standalone Angular component to render for each block. It injects the\n * per-block context via `inject(BLOK_BLOCK_CONTEXT)`.\n */\n component: Type<unknown>;\n /**\n * Static members of core's tool contract, forwarded verbatim onto the\n * generated tool class — the single channel for everything core reads off the\n * CLASS rather than the instance (`ownsChildren`, `keepsChildrenOnEnter`,\n * `conversionConfig`, `pasteConfig`, `sanitize`, `shortcut`, `upgradeData`…).\n * Without it the only way to declare one was to subclass the generated class.\n *\n * `keepsChildrenOnEnter` is the per-tool Enter POLICY: declare it and Enter on\n * this container's empty LAST child creates the new line INSIDE the container\n * instead of escaping to the container's parent (Blok's default, which is\n * Notion's callout behaviour). Core cannot read that off the DOM — a callout\n * renders the same `data-blok-nested-blocks` slot as a column yet wants the\n * escape — so before it existed a layout container (a card, a `steps` block)\n * had to hijack the editor-global `config.onEnter` and re-derive containment.\n *\n * `toolbox` and `isReadOnlySupported` are owned by the factory and cannot be\n * overridden here (see {@link BlockToolStatics}).\n */\n statics?: BlockToolStatics;\n /**\n * The element the +/drag toolbar should vertically center on — core's\n * `getToolbarAnchorElement` hook, resolved against this block's host element\n * on every call (never cached, so it tracks re-renders).\n *\n * A container block whose own chrome is not editable needs it: with no anchor,\n * core centers the toolbar on the first `[contenteditable]` under the host,\n * which for a container is its FIRST CHILD BLOCK. Return `null`/`undefined`\n * (or omit the field) to keep core's default.\n * @param host - this block's mutation-free host element\n * @param block - this block's per-block API\n */\n getToolbarAnchorElement?: (host: HTMLElement, block: BlockAPI) => HTMLElement | null | undefined;\n /**\n * Enter (or Cmd/Ctrl+Enter) on this block while it is the keyboard\n * navigation target — core's `onNavigationEnter` hook. Return true when the\n * block handled it (e.g. opened a link); omit it, or return false, to let\n * core put the caret in the block.\n * @param event - the Enter keydown\n * @param block - this block's per-block API\n */\n onNavigationEnter?: (event: KeyboardEvent, block: BlockAPI) => boolean;\n /** Optional lifecycle callbacks mapped from Blok's block hooks. */\n onRendered?: (block: BlockAPI) => void;\n /**\n * Fired ONCE per block instance, once the component's DOM (and, for a\n * container, the child holders its `ctx.mountChildren` adopted) exists.\n * Angular mounts the block synchronously while core is still inside\n * `render()`, so this lands with `rendered()` — the first hook at which the\n * host is also in the document. The React and Vue adapters spell the same\n * contract; there it is genuinely LATER than `onRendered`, because their\n * portals commit a frame after core returns.\n *\n * It is also the create-vs-restore signal: `context.origin` says whether the\n * author just made this block (`user`/`api`/`convert`) or the document is\n * being re-materialised (`load`/`replay`/`paste`) — so a container can seed\n * its default children here exactly once, without the \"children are\n * transiently empty during a replay\" trap.\n * @example\n * ```ts\n * onMounted: (block, { origin, api }) => {\n * if (origin === 'user' && block.getChildren().length === 0) {\n * api.blocks.insertInsideParent(block.id);\n * }\n * }\n * ```\n */\n onMounted?: (block: BlockAPI, context: AngularBlockMountedContext) => void;\n /**\n * The SEEDING hook: `onMounted`, narrowed to a genuine creation. Fired ONCE\n * per block instance, once the component's DOM exists, and only when this\n * instance is the author making a new block (`origin` of `user`, `api` or\n * `convert`) — never for a `load`/`replay`/`paste` restore, and never for the\n * off-tree `probe` instance core builds to read a tool's default data.\n *\n * That predicate is why the hook exists rather than leaving every block to\n * read `context.origin` in `onMounted`: the intuitive `origin === 'user'` test\n * is wrong. It drops `api.blocks.insert('steps')` and turn-into, so a\n * container seeded that way comes up empty for every path except a keystroke.\n * Core refused to ship that axis into its own `column`/`column_list`; this\n * encodes the correct one once, here.\n *\n * The `context` is the same object {@link CreateAngularBlockSpec.onMounted}\n * receives, so a block that only seeds can read `origin` for finer decisions.\n * @example\n * ```ts\n * onCreated: (block, { api }) => {\n * if (block.getChildren().length === 0) {\n * api.blocks.insertInsideParent(block.id);\n * }\n * }\n * ```\n */\n onCreated?: (block: BlockAPI, context: AngularBlockMountedContext) => void;\n onMoved?: (block: BlockAPI) => void;\n onRemoved?: (block: BlockAPI) => void;\n}\n\n/**\n * Author a first-party Angular block. Returns a `BlockToolConstructable`\n * registered exactly like a vanilla tool (`tools: { type: { class:\n * createAngularBlock(...) } }`).\n *\n * The factory owns the host element (`data-blok-mutation-free`), a frozen\n * defaults-filled data mirror, and signals the component reads. It mounts the\n * component into the host via the editor's shared portal registry (the analog of\n * Vue's Teleport registry), bridging Blok's block lifecycle to Angular:\n * - `render()` creates the host and registers the portal entry (mounted sync).\n * - `setData()` dedups, swaps the reactive snapshot, flushes CD, resolves true.\n * - `save()` returns the complete frozen mirror (never the DOM, never partial).\n * - `commit()` merges a patch and fires `dispatchChange` exactly once.\n * - `setReadOnly()` flips a reactive flag and flushes CD (in-place, no remount).\n * - `removed()`/`destroy()` unregister the portal (deterministic unmount).\n */\nexport function createAngularBlock<Data = BlockToolData>(\n spec: CreateAngularBlockSpec<Data>\n): (new (options: BlockToolConstructorOptions) => {\n render(): HTMLElement;\n save(): BlockToolData;\n setData(newData: BlockToolData): Promise<boolean>;\n setReadOnly(state: boolean): void;\n getToolbarAnchorElement(): HTMLElement | undefined;\n onNavigationEnter(event: KeyboardEvent): boolean;\n rendered(): void;\n moved(): void;\n removed(): void;\n destroy(): void;\n}) & BlockToolStatics & {\n readonly __isBlokAngularBlock: true;\n readonly toolbox: ToolboxConfig | undefined;\n readonly isReadOnlySupported: boolean;\n} {\n const AngularBlockTool = class AngularBlockTool {\n /** Marker so the directive can detect Angular-block tools and inject the registry. */\n public static readonly __isBlokAngularBlock = true as const;\n\n public static get toolbox(): ToolboxConfig | undefined {\n return spec.toolbox;\n }\n\n /**\n * Angular blocks support read-only mode: `setReadOnly` flips a reactive flag\n * the component reads, so the block re-renders read-only IN PLACE. Without\n * this static, core's ReadOnly module throws when read-only is enabled and an\n * Angular block is present.\n */\n public static get isReadOnlySupported(): boolean {\n return true;\n }\n\n private readonly blockApi: BlockAPI;\n /** The editor-level API, handed to the component as `ctx.api`. */\n private readonly api: API;\n private readonly registry: BlockPortalRegistry | undefined;\n private readonly pointerDrag: () => boolean;\n private readonly dataSig: WritableSignal<Readonly<Data>>;\n private readonly readOnlySig: WritableSignal<boolean>;\n private readonly ctx: AngularBlockRenderContext<Data>;\n private mirror: Readonly<Data>;\n /** Dedup baseline: skip a redundant flush of identical data. */\n private lastRendered: Readonly<Data>;\n private hostEl: HTMLElement | null = null;\n /** Last host passed to ctx.mountChildren, re-mounted on each data change. */\n private childHost: HTMLElement | null = null;\n /** Element the component handed to ctx.setToolbarAnchor, if any. */\n private anchorEl: HTMLElement | null = null;\n /**\n * Last per-child decorators passed to ctx.mountChildren; BOTH re-applied on\n * every remount (the author calls mountChildren once, the factory re-runs the\n * mount on each data change).\n */\n private childAttributes: ChildAttributesFn | undefined;\n private childContentAttributes: ChildAttributesFn | undefined;\n /** What the last decoration pass wrote, so a dropped key is cleaned up. */\n private readonly childLedger = createChildDecorationLedger();\n /** Why core built this instance — gates `onCreated`, handed to `onMounted`. */\n private readonly origin: BlockOrigin;\n /** True once the post-mount hooks fired; a repeated rendered() must not re-fire them. */\n private mountSignalled = false;\n /** True while a pointer drag suppresses dispatchChange. */\n private pendingDispatch = false;\n\n public constructor(options: BlockToolConstructorOptions) {\n this.blockApi = options.block;\n\n const config = (options.config ?? {}) as Record<string, unknown>;\n\n this.registry = config[BLOK_PORTAL_REGISTRY_CONFIG_KEY] as BlockPortalRegistry | undefined;\n\n this.api = options.api;\n\n // Read the LIVE pointer-drag flag so a mid-drag commit can be deferred\n // (core silently drops a dispatchChange while a drag is active).\n const drag = options.api as unknown as { blocks?: { isPointerDragActive?: boolean } } | undefined;\n\n this.pointerDrag = (): boolean => drag?.blocks?.isPointerDragActive === true;\n\n this.mirror = fillDefaults<Data>(spec.propSchema, (options.data ?? {}) as Record<string, unknown>);\n this.lastRendered = this.mirror;\n this.dataSig = signal(this.mirror);\n this.readOnlySig = signal(options.readOnly);\n // Absent origin means a caller that predates the signal; 'api' is core's\n // own default, so it is never mistaken for a user gesture.\n this.origin = options.origin ?? 'api';\n\n this.ctx = {\n data: this.dataSig.asReadonly(),\n commit: this.commit,\n block: this.blockApi,\n api: this.api,\n readOnly: this.readOnlySig.asReadonly(),\n mountChildren: this.mountChildren,\n setToolbarAnchor: this.setToolbarAnchor,\n };\n }\n\n public render(): HTMLElement {\n const host = document.createElement('div');\n\n // Core's MutationObserver ignores this subtree, so Angular's DOM writes\n // never register as a user edit.\n host.setAttribute('data-blok-mutation-free', 'true');\n this.hostEl = host;\n\n this.registry?.register(this.blockApi.id, {\n hostEl: host,\n component: spec.component,\n context: this.ctx as AngularBlockRenderContext<unknown>,\n });\n\n return host;\n }\n\n public rendered(): void {\n spec.onRendered?.(this.blockApi);\n\n // register() mounted the component and ran its first change detection\n // synchronously inside render(), and core has now put the host in the\n // document — so this is the settled moment. Once per instance: core\n // re-runs rendered() for a re-materialised block, and a repeated creation\n // signal would seed a container's default children twice. With no\n // registry (vanilla core, no directive) nothing was ever mounted, so\n // there is no settle to report — matching React/Vue, where the signal\n // originates in the component itself.\n if (this.registry === undefined || this.mountSignalled) {\n return;\n }\n\n this.mountSignalled = true;\n\n const context = { origin: this.origin, api: this.api };\n\n spec.onMounted?.(this.blockApi, context);\n\n // Creation-only, and after onMounted: a seeding hook must see whatever\n // the mount hook already put in place.\n if (CREATION_ORIGINS.has(this.origin)) {\n spec.onCreated?.(this.blockApi, context);\n }\n }\n\n public save(): BlockToolData {\n return this.mirror as BlockToolData;\n }\n\n public async setData(newData: BlockToolData): Promise<boolean> {\n const next = fillDefaults<Data>(spec.propSchema, (newData ?? {}) as Record<string, unknown>);\n\n // Dedup: identical data → skip the flush, but still return true so core\n // keeps the block in place (no remount).\n if (deepEqual(next, this.lastRendered)) {\n return true;\n }\n\n this.mirror = next;\n this.lastRendered = next;\n this.dataSig.set(next);\n // Synchronous CD: core drives setData outside NgZone, so nothing else\n // schedules a render. Never throw (a throw would make core remount).\n this.registry?.flush(this.blockApi.id);\n this.remountChildren();\n\n // Resolve after a microtask for interface symmetry with the async core\n // setData contract; CD has already flushed synchronously above.\n await Promise.resolve();\n\n return true;\n }\n\n /**\n * In-place read-only toggle. Flips the reactive flag the component reads via\n * `ctx.readOnly`, then flushes CD so the block re-renders read-only WITHOUT a\n * remount (ephemeral state survives). A prototype method (not an arrow field)\n * so core's `supportsInPlaceReadOnly` — which probes the PROTOTYPE — selects\n * the in-place path.\n */\n public setReadOnly(state: boolean): void {\n this.readOnlySig.set(state);\n this.registry?.flush(this.blockApi.id);\n }\n\n /**\n * Core's toolbar-anchor hook. Always defined so the delegation is one\n * `typeof … === 'function'` probe away, and always resolved fresh against\n * the LIVE host — the anchor element is Angular-rendered, so it does not\n * exist yet when the tool is constructed and may be replaced on any change\n * detection pass. A spec without a resolver returns undefined, which is\n * exactly what core's default positioning already assumes.\n */\n public getToolbarAnchorElement(): HTMLElement | undefined {\n /**\n * An element the component handed over wins — it is the exact node, chosen\n * from inside the template. `isConnected` is the guard that matters: a\n * component that re-renders its anchor can leave a detached node here, and\n * positioning the toolbar against one silently parks it at 0,0.\n */\n const declared = this.anchorEl;\n\n if (declared !== null && declared.isConnected) {\n return declared;\n }\n\n const host = this.hostEl;\n\n if (host === null || spec.getToolbarAnchorElement === undefined) {\n return undefined;\n }\n\n return spec.getToolbarAnchorElement(host, this.blockApi) ?? undefined;\n }\n\n /**\n * Core's navigation-mode Enter hook. Only a real `true` from the spec\n * counts as handled.\n */\n public onNavigationEnter(event: KeyboardEvent): boolean {\n return spec.onNavigationEnter?.(event, this.blockApi) === true;\n }\n\n /**\n * `ctx.setToolbarAnchor`. A bound field so the context object handed through\n * DI keeps a stable identity.\n * @param element - the anchor element, or null to fall back to the spec hook\n */\n private readonly setToolbarAnchor = (element: HTMLElement | null): void => {\n this.anchorEl = element;\n };\n\n public moved(): void {\n // No remount: core relocates the host element; the mounted view rides along\n // as its DOM children.\n spec.onMoved?.(this.blockApi);\n }\n\n public removed(): void {\n // Ownership-scoped: core composes a REPLACEMENT block (which mounts under\n // the SAME id) before it tears this one down, so an unqualified unregister\n // here would destroy the live componentRef and blank the block.\n this.registry?.unregister(this.blockApi.id, this.hostEl ?? undefined);\n spec.onRemoved?.(this.blockApi);\n }\n\n public destroy(): void {\n // Idempotent with removed(); unregister is safe when already absent.\n this.registry?.unregister(this.blockApi.id, this.hostEl ?? undefined);\n }\n\n /**\n * Container blocks: remember the host (and any per-child decorator) and\n * (re)mount the real child holders.\n */\n private readonly mountChildren = (\n host: HTMLElement,\n childAttributes?: ChildAttributesFn,\n childContentAttributes?: ChildAttributesFn\n ): void => {\n this.childHost = host;\n this.childAttributes = childAttributes;\n this.childContentAttributes = childContentAttributes;\n host.setAttribute(DATA_ATTR.nestedBlocks, '');\n this.remountChildren();\n };\n\n private remountChildren(): void {\n if (this.childHost === null) {\n return;\n }\n\n const children = this.blockApi.getChildren();\n\n // A slotless child's own children live in this slot too. Decoration and\n // the mounted event stay per DIRECT child.\n mountChildBlocks(this.childHost, withSlotlessDescendants(children, id => this.api.blocks.getChildren(id)));\n applyChildDecoration(this.childLedger, children, {\n childAttributes: this.childAttributes,\n childContentAttributes: this.childContentAttributes,\n });\n emitChildrenMounted(this.api, this.blockApi.id, children);\n }\n\n /**\n * The only data write path. Merges the patch into the frozen mirror, swaps\n * the reactive snapshot, flushes CD, and fires dispatchChange EXACTLY once —\n * deferring it while a pointer drag is active (core would otherwise silently\n * drop it).\n */\n private readonly commit = (patch: Partial<Data>): void => {\n const next = fillDefaults<Data>(spec.propSchema, {\n ...(this.mirror as Record<string, unknown>),\n ...(patch as Record<string, unknown>),\n });\n\n // Idempotent: a patch that changes nothing is a full no-op — no signal\n // swap, no CD flush, no dispatchChange — so an effect echoing the current\n // value back through commit can never loop.\n if (deepEqual(next, this.mirror)) {\n return;\n }\n\n this.mirror = next;\n this.lastRendered = next;\n this.dataSig.set(next);\n this.registry?.flush(this.blockApi.id);\n this.remountChildren();\n this.flushDispatch();\n };\n\n /** Dispatch the change, or retry on the next frame if a drag is in progress. */\n private flushDispatch(): void {\n if (!this.pointerDrag()) {\n this.pendingDispatch = false;\n this.blockApi.dispatchChange();\n\n return;\n }\n\n if (this.pendingDispatch) {\n return;\n }\n\n this.pendingDispatch = true;\n\n const retry = (): void => {\n if (this.pointerDrag()) {\n requestAnimationFrame(retry);\n\n return;\n }\n\n this.pendingDispatch = false;\n this.blockApi.dispatchChange();\n };\n\n requestAnimationFrame(retry);\n }\n };\n\n // Forward the authored statics onto the generated class. `defineProperty`\n // (not assignment) because `toolbox`/`isReadOnlySupported` are accessors and a\n // plain write would throw in strict mode; the reserved list keeps a stray bag\n // from taking those — or the adapter's own marker — over.\n for (const [key, value] of Object.entries(spec.statics ?? {})) {\n if (RESERVED_STATICS.includes(key)) {\n continue;\n }\n\n Object.defineProperty(AngularBlockTool, key, {\n value,\n writable: true,\n enumerable: true,\n configurable: true,\n });\n }\n\n return AngularBlockTool;\n}\n","import type { Blok } from '@bloklabs/core';\n// packages/angular/src/useBlocks.ts\nimport { DestroyRef, effect, inject, signal, type Signal } from '@angular/core';\n\nimport { changeTouchesSubtree, createBlocksApiForEditor, EMPTY_API } from '../adapters-contract';\n\nimport type { UseBlocksApi } from './blocks-snapshot';\n\nconst BLOCK_CHANGED_EVENT = 'block changed';\n\n/** Options for {@link injectBlocks}. */\nexport interface InjectBlocksOptions {\n /**\n * Invalidate reads only for changes inside the subtree rooted at this block id\n * (the block itself or any descendant). Omit — or pass `null` — for the\n * document-wide default.\n *\n * This bounds REACTIVITY, not reads: the returned API still sees the whole\n * tree, so a scoped consumer can still `getById` anything. Reach for it in a\n * container block that renders only its own children — unscoped, such a block\n * invalidates on every keystroke anywhere in the document, and a page of N\n * containers turns one keystroke into N re-renders.\n *\n * Accepted as a plain value or a signal (like `editor`) and read at EMIT time,\n * so changing it takes effect immediately with no re-subscription.\n *\n * A change whose block cannot be placed in the tree (a removal that emits\n * after the block is gone) counts as in-scope: skipping it would leave a\n * container rendering a child that no longer exists.\n */\n within?: Signal<string | null> | string | null;\n}\n\n/**\n * Angular factory exposing an id/parentId-relative, reactive view of the block\n * tree. Reads refresh whenever the editor emits `block changed`; mutators route\n * through the editor-level `blocks` API (core's chokepoints), so undo/redo and\n * Yjs sync are inherited rather than re-implemented.\n *\n * The block-tree logic is framework-agnostic and lives in the shared\n * {@link createBlocksApiForEditor} core — the SAME implementation behind React's\n * and Vue's `useBlocks`, so all three adapters expose the identical 28-method\n * surface and cannot drift. This wrapper supplies only Angular's reactivity:\n *\n * - A private `version` signal is bumped on every `block changed`. The shared API\n * is built with an `onRead` seam (`() => { version() }`) that every read method\n * calls, so reading inside a `computed`/template tracks `version` and re-runs on\n * each structural mutation.\n * - The bound API is rebuilt (via `bindToEditor`, called eagerly on first call and\n * then tracked by an `effect` for subsequent identity changes) when the editor\n * IDENTITY changes; the returned facade is stable across that swap.\n *\n * Call it in an injection context (component constructor / field initializer),\n * passing the editor signal (e.g. `BlokEditorComponent.instance` /\n * `BlokContentDirective.instance`). Pre-ready (editor null) the bound API is the\n * shared {@link EMPTY_API}: every mutator a no-op, reads empty/null — except\n * `transact`/`transactWithoutCapture`, which still run their callback.\n *\n * Note: Angular 20's `effect()` is scheduled (not eager) — it does not fire\n * synchronously on first call. The initial binding therefore runs synchronously\n * in the `injectBlocks` body itself (mirroring Vue's `{ immediate: true }` watch),\n * and the effect re-binds only on subsequent editor identity changes. When the\n * effect fires for the first time with the same editor already bound, the guard\n * `ed === sub.editor` makes it a no-op, so no double-subscription occurs.\n *\n * @param editor - a signal of the Blok instance, or null pre-ready\n * @param options - reactivity options; see {@link InjectBlocksOptions.within} to\n * scope invalidation to one block's subtree\n */\nexport function injectBlocks(\n editor: Signal<Blok | null>,\n options: InjectBlocksOptions = {}\n): UseBlocksApi {\n /**\n * The scope, resolved per emission so a signal `within` takes effect with no\n * re-subscription. A signal is a zero-arg function, which is how it is told\n * apart from a plain id.\n */\n const resolveWithin = (): string | null =>\n (typeof options.within === 'function' ? options.within() : options.within) ?? null;\n\n // Bumped on every `block changed`; the shared API's read methods touch it (via\n // the onRead seam) so template/computed reads stay reactive.\n const version = signal(0);\n const touch = (): void => {\n version();\n };\n\n // The API bound to the CURRENT editor; EMPTY_API while null. A signal so the\n // facade's reads track the editor-identity swap.\n const bound = signal<UseBlocksApi>(EMPTY_API);\n\n // One subscription record (no `let` reassignment), re-bound on editor change.\n const sub: { editor: Blok | null; handler: ((payload?: unknown) => void) | null } = { editor: null, handler: null };\n\n const unsubscribe = (): void => {\n if (sub.editor !== null && sub.handler !== null) {\n sub.editor.off(BLOCK_CHANGED_EVENT, sub.handler);\n }\n sub.editor = null;\n sub.handler = null;\n };\n\n /**\n * Bind to `ed` if the identity has changed. Guards `ed === sub.editor` so a\n * deferred first effect-run with the same editor already bound is a no-op\n * (no double-subscription). Called synchronously on first call (immediate\n * binding) and then re-tracked by the effect below (future identity changes).\n */\n const bindToEditor = (ed: Blok | null): void => {\n if (ed === sub.editor) {\n return; // Same editor already bound; nothing to do.\n }\n\n unsubscribe();\n // A changed editor identity is itself a reason to re-read.\n version.update((v) => v + 1);\n\n if (ed === null) {\n bound.set(EMPTY_API);\n\n return;\n }\n\n const handler = (payload?: unknown): void => {\n const within = resolveWithin();\n\n if (within !== null && !changeTouchesSubtree(ed, payload, within)) {\n return;\n }\n\n version.update((v) => v + 1);\n };\n\n ed.on(BLOCK_CHANGED_EVENT, handler);\n sub.editor = ed;\n sub.handler = handler;\n bound.set(createBlocksApiForEditor(ed, touch));\n };\n\n // Run the initial binding SYNCHRONOUSLY so the returned facade is immediately\n // usable (Angular's effect() is deferred — it does not fire on the same tick).\n // This mirrors Vue's `watch(..., { immediate: true })`.\n bindToEditor(editor());\n\n // Re-bind when the editor identity changes. Angular 20 permits signal writes\n // inside effect() by default (allowSignalWrites option was removed in v20).\n effect(() => {\n bindToEditor(editor());\n });\n\n inject(DestroyRef).onDestroy(unsubscribe);\n\n // A stable facade whose methods delegate to the currently-bound API. Reading\n // `bound()` tracks the editor swap; shared reads track `version` via onRead.\n // Every key listed EXPLICITLY (no spread) so a forgotten delegation is a\n // COMPILE error against UseBlocksApi rather than a silently-missing method.\n return {\n getById: (id) => bound().getById(id),\n getChildren: (parentId) => bound().getChildren(parentId),\n insert: (spec) => bound().insert(spec),\n insertMany: (specs) => bound().insertMany(specs),\n insertTree: (spec) => bound().insertTree(spec),\n insertMarkdown: (markdown, options) => bound().insertMarkdown(markdown, options),\n exportMarkdown: () => bound().exportMarkdown(),\n move: (id, target) => bound().move(id, target),\n nest: (id, parentId) => bound().nest(id, parentId),\n unnest: (id) => bound().unnest(id),\n remove: (id) => bound().remove(id),\n update: (id, data, tunes) => bound().update(id, data, tunes),\n convert: (id, newType, dataOverrides, options) => bound().convert(id, newType, dataOverrides, options),\n transact: (fn) => bound().transact(fn),\n transactWithoutCapture: (fn, options) => bound().transactWithoutCapture(fn, options),\n getBlocksCount: () => bound().getBlocksCount(),\n getCurrentBlockIndex: () => bound().getCurrentBlockIndex(),\n getBlockByIndex: (index) => bound().getBlockByIndex(index),\n getBlockByElement: (element) => bound().getBlockByElement(element),\n getBlockData: (id) => bound().getBlockData(id),\n getBlockIndex: (id) => bound().getBlockIndex(id),\n composeBlockData: (toolName) => bound().composeBlockData(toolName),\n renderFromHTML: (html) => bound().renderFromHTML(html),\n insertOutputData: (blocks, options) => bound().insertOutputData(blocks, options),\n splitBlock: (currentBlockId, currentBlockData, newBlockType, newBlockData, insertIndex) =>\n bound().splitBlock(currentBlockId, currentBlockData, newBlockType, newBlockData, insertIndex),\n insertInsideParent: (parentId, insertIndex, childData) =>\n bound().insertInsideParent(parentId, insertIndex, childData),\n render: (data) => bound().render(data),\n clear: () => bound().clear(),\n isSyncingFromYjs: () => bound().isSyncingFromYjs(),\n };\n}\n","// packages/angular/src/useBlokReady.ts\nimport { DestroyRef, ElementRef, afterNextRender, inject, signal, type Signal } from '@angular/core';\n\nimport { Blok as BlokRuntime } from '@bloklabs/core';\n\n/** How the caller names the DOM scope to observe. */\nexport type BlokReadyScope =\n | (() => Element | ElementRef<Element> | null | undefined)\n | ElementRef<Element>\n | Element\n | null;\n\n/** Options accepted by {@link injectBlokReady}. */\nexport interface InjectBlokReadyOptions {\n /**\n * Restrict the wait to editors mounted inside this element. Accepts an\n * element, an `ElementRef`, or a getter/signal returning either — the getter\n * form lets you pass `() => this.scopeRef?.nativeElement` from a field\n * initializer, before the view exists. It is re-read on every readiness\n * change.\n *\n * Omit it to observe every editor on the page. Passing it while it still\n * resolves to null reports NOT ready — an unresolved scope must never fall\n * back to the page-global one.\n */\n within?: BlokReadyScope;\n /**\n * `'ready'` (default) settles when each editor has finished booting.\n * `'rendered'` also waits for its content to be in the DOM and re-arms on\n * every post-boot re-render.\n */\n settleOn?: 'ready' | 'rendered';\n}\n\n/**\n * Resolves the caller's scope description to an element, or null when it is\n * not available yet.\n * @param within - the scope description passed in options\n */\nfunction resolveScope(within: BlokReadyScope): Element | null {\n const value = typeof within === 'function' ? within() : within;\n\n if (value === null || value === undefined) {\n return null;\n }\n\n return value instanceof ElementRef ? value.nativeElement : value;\n}\n\n/**\n * Angular factory exposing the live readiness of the Blok editors in a DOM\n * scope as a boolean signal.\n *\n * The readiness logic itself is framework-agnostic and lives in core\n * (`Blok.readyState` / `Blok.subscribeReady`) — the SAME implementation behind\n * React's and Vue's `useBlokReady`, so the three adapters cannot drift. This\n * wrapper supplies only Angular's reactivity: a signal re-read on every\n * registry change, unsubscribed through the injector's `DestroyRef`.\n *\n * Call it in an injection context (component constructor / field initializer).\n * The signal starts `false` and takes its first real reading in\n * `afterNextRender` — browser-only by contract, and late enough for a\n * `@ViewChild` scope to exist. Over-waiting is safe; under-waiting is a bug.\n * @param options - scope and readiness depth\n */\nexport function injectBlokReady(options: InjectBlokReadyOptions = {}): Signal<boolean> {\n const { within, settleOn } = options;\n const ready = signal(false);\n\n const read = (): void => {\n const scope = within === undefined ? null : resolveScope(within);\n\n // A scope that was asked for but has not resolved yet is NOT the global\n // scope — reporting ready here would gate on the wrong set of editors.\n ready.set(within !== undefined && scope === null\n ? false\n : BlokRuntime.readyState({\n within: scope,\n settleOn,\n }).ready);\n };\n\n inject(DestroyRef).onDestroy(BlokRuntime.subscribeReady(read));\n afterNextRender(read);\n\n return ready.asReadonly();\n}\n"],"mappings":"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"}
|