@bloklabs/angular 1.3.0 → 1.4.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/package.json CHANGED
@@ -1,14 +1,34 @@
1
1
  {
2
2
  "name": "@bloklabs/angular",
3
- "version": "1.3.0",
4
- "description": "Angular bindings for the Blok editor (APF partial-Ivy bundle)",
3
+ "version": "1.4.0",
4
+ "description": "Angular block editor — official Angular bindings for Blok, the headless Notion-like rich text editor. Standalone components that render blocks and save to JSON (APF partial-Ivy bundle).",
5
5
  "license": "Apache-2.0",
6
6
  "author": "JackUait",
7
+ "homepage": "https://blokeditor.com",
7
8
  "repository": {
8
9
  "type": "git",
9
10
  "url": "git+https://github.com/JackUait/blok.git",
10
11
  "directory": "packages/angular"
11
12
  },
13
+ "bugs": {
14
+ "url": "https://github.com/JackUait/blok/issues"
15
+ },
16
+ "keywords": [
17
+ "blok",
18
+ "angular",
19
+ "angular-component",
20
+ "block-editor",
21
+ "rich-text-editor",
22
+ "wysiwyg",
23
+ "editor",
24
+ "notion",
25
+ "notion-like",
26
+ "headless",
27
+ "block-based",
28
+ "contenteditable",
29
+ "json",
30
+ "typescript"
31
+ ],
12
32
  "publishConfig": {
13
33
  "access": "public"
14
34
  },
@@ -16,7 +36,7 @@
16
36
  "@angular/common": ">=20 <23",
17
37
  "@angular/core": ">=20 <23",
18
38
  "@angular/forms": ">=20 <23",
19
- "@bloklabs/core": "1.3.0"
39
+ "@bloklabs/core": "1.4.0"
20
40
  },
21
41
  "module": "fesm2022/bloklabs-angular.mjs",
22
42
  "typings": "./index.d.ts",
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { AfterViewInit, EventEmitter, OnDestroy, InjectionToken, EnvironmentProviders, Type, Signal } from '@angular/core';
2
+ import { AfterViewInit, EventEmitter, OnDestroy, InjectionToken, EnvironmentProviders, Type, Signal, ElementRef } from '@angular/core';
3
3
  import { ControlValueAccessor } from '@angular/forms';
4
4
  import { BlokConfig, EditorWidth, Blok, OutputData, API, BlockMutationEvent, ResolvedTheme, BlocksRenderedPayload, BlockRenderedPayload, OutputBlockData, ThemeMode, LooseOutputData, BlockToolData, BlockTuneData, MarkdownImportConfig, ToolboxConfig, BlockAPI, BlockToolConstructorOptions } from '@bloklabs/core';
5
5
 
@@ -18,8 +18,16 @@ type BlokAngularConfig = Omit<BlokConfig, 'holder'> & {
18
18
  * `BlokEditor`). Delegates instance lifecycle to an internal `BlokContentDirective`
19
19
  * and layers the typed reactive input/output API on top.
20
20
  *
21
- * Reactive inputs (`readOnly`, `theme`, `width`, `placeholder`, `autofocus`) are
22
- * synced in place after mount via effects; everything else seeds construction.
21
+ * Reactive inputs (`readOnly`, `hideToolbar`, `inlineToolbar`, `theme`,
22
+ * `width`, `placeholder`, `autofocus`, `styleTokens`, `i18n`, `data`) are
23
+ * synced in place after mount via effects — `hideToolbar` through
24
+ * `editor.toolbar.setHidden()`, `inlineToolbar` through
25
+ * `editor.tools.setInlineToolbar()` (content-compared),
26
+ * `styleTokens` through `editor.tokens.set()` (replace semantics),
27
+ * `i18n` through `editor.i18n.update()` (deep-equal–deduped; seeded at
28
+ * construction so the locale resolves during boot) and `data`
29
+ * through `editor.render()` (deep-equal–deduped); everything else seeds
30
+ * construction.
23
31
  *
24
32
  * Implementation note: classic `@Input()`/`@ViewChild()` decorators are used
25
33
  * (not signal `input()`/`viewChild()`) for JIT compatibility — see
@@ -68,7 +76,11 @@ declare class BlokEditorComponent implements AfterViewInit, ControlValueAccessor
68
76
  */
69
77
  onBeforePaste?: (html: string) => string | null;
70
78
  private readonly readOnly$;
71
- set readOnly(value: boolean | undefined);
79
+ set readOnly(value: BlokConfig['readOnly'] | undefined);
80
+ private readonly hideToolbar$;
81
+ set hideToolbar(value: boolean | undefined);
82
+ private readonly inlineToolbar$;
83
+ set inlineToolbar(value: boolean | string[] | undefined);
72
84
  private readonly theme$;
73
85
  set theme(value: ThemeMode | undefined);
74
86
  private readonly width$;
@@ -82,6 +94,15 @@ declare class BlokEditorComponent implements AfterViewInit, ControlValueAccessor
82
94
  */
83
95
  private readonly styleTokens$;
84
96
  set styleTokens(value: Record<string, string> | undefined);
97
+ /**
98
+ * Locale, host message overrides and text direction. `config.i18n` was
99
+ * consumed once at boot, so a host driving a language switcher had to
100
+ * recreate the editor (losing caret, focus and undo stack) to relabel the
101
+ * UI; this drives the runtime `i18n.update` API instead. `defaultLocale` is
102
+ * not forwarded — it only affects the INITIAL locale resolution.
103
+ */
104
+ private readonly i18n$;
105
+ set i18n(value: BlokConfig['i18n'] | undefined);
85
106
  private readonly autofocus$;
86
107
  set autofocus(value: boolean | undefined);
87
108
  private readonly data$;
@@ -89,7 +110,7 @@ declare class BlokEditorComponent implements AfterViewInit, ControlValueAccessor
89
110
  tools?: BlokConfig['tools'];
90
111
  /**
91
112
  * Escape hatch: a full config object for keys without a dedicated input
92
- * (i18n, sanitizer, minHeight, inlineToolbar, …). Layered between provideBlok
113
+ * (sanitizer, minHeight, …). Layered between provideBlok
93
114
  * defaults and the discrete inputs.
94
115
  */
95
116
  config?: Partial<BlokAngularConfig>;
@@ -103,6 +124,12 @@ declare class BlokEditorComponent implements AfterViewInit, ControlValueAccessor
103
124
  private lastRenderedData?;
104
125
  /** Last token set pushed through `tokens.set`, for deep-equal deduping. */
105
126
  private appliedTokens?;
127
+ /** Last i18n config pushed through `i18n.update`, for deep-equal deduping. */
128
+ private appliedI18n?;
129
+ /** Editor instance the i18n baseline above belongs to. */
130
+ private i18nAppliedFor;
131
+ /** Last value pushed through `tools.setInlineToolbar`, for content-compare deduping. */
132
+ private appliedInlineToolbar?;
106
133
  private seededEditor;
107
134
  private renderChain;
108
135
  /** Registered by `ControlValueAccessor.registerOnChange` (Angular forms). */
@@ -141,7 +168,7 @@ declare class BlokEditorComponent implements AfterViewInit, ControlValueAccessor
141
168
  /** Form disabled state maps to the editor's read-only mode (via the readOnly effect). */
142
169
  setDisabledState(isDisabled: boolean): void;
143
170
  static ɵfac: i0.ɵɵFactoryDeclaration<BlokEditorComponent, never>;
144
- static ɵcmp: i0.ɵɵComponentDeclaration<BlokEditorComponent, "blok-editor", ["blok"], { "onBeforeRender": { "alias": "onBeforeRender"; "required": false; }; "onBeforePaste": { "alias": "onBeforePaste"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; "theme": { "alias": "theme"; "required": false; }; "width": { "alias": "width"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "styleTokens": { "alias": "styleTokens"; "required": false; }; "autofocus": { "alias": "autofocus"; "required": false; }; "data": { "alias": "data"; "required": false; }; "tools": { "alias": "tools"; "required": false; }; "config": { "alias": "config"; "required": false; }; "recreateKey": { "alias": "recreateKey"; "required": false; }; }, { "ready": "ready"; "dataChange": "dataChange"; "save": "save"; "change": "change"; "afterRender": "afterRender"; "themeChange": "themeChange"; "blocksRendered": "blocksRendered"; "blockRendered": "blockRendered"; }, never, never, true, never>;
171
+ static ɵcmp: i0.ɵɵComponentDeclaration<BlokEditorComponent, "blok-editor", ["blok"], { "onBeforeRender": { "alias": "onBeforeRender"; "required": false; }; "onBeforePaste": { "alias": "onBeforePaste"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; "hideToolbar": { "alias": "hideToolbar"; "required": false; }; "inlineToolbar": { "alias": "inlineToolbar"; "required": false; }; "theme": { "alias": "theme"; "required": false; }; "width": { "alias": "width"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "styleTokens": { "alias": "styleTokens"; "required": false; }; "i18n": { "alias": "i18n"; "required": false; }; "autofocus": { "alias": "autofocus"; "required": false; }; "data": { "alias": "data"; "required": false; }; "tools": { "alias": "tools"; "required": false; }; "config": { "alias": "config"; "required": false; }; "recreateKey": { "alias": "recreateKey"; "required": false; }; }, { "ready": "ready"; "dataChange": "dataChange"; "save": "save"; "change": "change"; "afterRender": "afterRender"; "themeChange": "themeChange"; "blocksRendered": "blocksRendered"; "blockRendered": "blockRendered"; }, never, never, true, never>;
145
172
  }
146
173
 
147
174
  /**
@@ -648,6 +675,47 @@ declare function createAngularBlock<Data = BlockToolData>(spec: CreateAngularBlo
648
675
  */
649
676
  declare function injectBlocks(editor: Signal<Blok | null>): UseBlocksApi;
650
677
 
678
+ /** How the caller names the DOM scope to observe. */
679
+ type BlokReadyScope = (() => Element | ElementRef<Element> | null | undefined) | ElementRef<Element> | Element | null;
680
+ /** Options accepted by {@link injectBlokReady}. */
681
+ interface InjectBlokReadyOptions {
682
+ /**
683
+ * Restrict the wait to editors mounted inside this element. Accepts an
684
+ * element, an `ElementRef`, or a getter/signal returning either — the getter
685
+ * form lets you pass `() => this.scopeRef?.nativeElement` from a field
686
+ * initializer, before the view exists. It is re-read on every readiness
687
+ * change.
688
+ *
689
+ * Omit it to observe every editor on the page. Passing it while it still
690
+ * resolves to null reports NOT ready — an unresolved scope must never fall
691
+ * back to the page-global one.
692
+ */
693
+ within?: BlokReadyScope;
694
+ /**
695
+ * `'ready'` (default) settles when each editor has finished booting.
696
+ * `'rendered'` also waits for its content to be in the DOM and re-arms on
697
+ * every post-boot re-render.
698
+ */
699
+ settleOn?: 'ready' | 'rendered';
700
+ }
701
+ /**
702
+ * Angular factory exposing the live readiness of the Blok editors in a DOM
703
+ * scope as a boolean signal.
704
+ *
705
+ * The readiness logic itself is framework-agnostic and lives in core
706
+ * (`Blok.readyState` / `Blok.subscribeReady`) — the SAME implementation behind
707
+ * React's and Vue's `useBlokReady`, so the three adapters cannot drift. This
708
+ * wrapper supplies only Angular's reactivity: a signal re-read on every
709
+ * registry change, unsubscribed through the injector's `DestroyRef`.
710
+ *
711
+ * Call it in an injection context (component constructor / field initializer).
712
+ * The signal starts `false` and takes its first real reading in
713
+ * `afterNextRender` — browser-only by contract, and late enough for a
714
+ * `@ViewChild` scope to exist. Over-waiting is safe; under-waiting is a bug.
715
+ * @param options - scope and readiness depth
716
+ */
717
+ declare function injectBlokReady(options?: InjectBlokReadyOptions): Signal<boolean>;
718
+
651
719
  /**
652
720
  * Context handed to a `createAngularBlock` component. Delivered via DI (the
653
721
  * BLOK_BLOCK_CONTEXT token) rather than @Input, because core constructs the tool
@@ -680,5 +748,5 @@ interface AngularBlockRenderContext<Data> {
680
748
  /** DI token carrying the per-block render context into the authored component. */
681
749
  declare const BLOK_BLOCK_CONTEXT: InjectionToken<AngularBlockRenderContext<unknown>>;
682
750
 
683
- export { BLOK_BLOCK_CONTEXT, BLOK_DEFAULT_CONFIG, BlokContentDirective, BlokEditorComponent, createAngularBlock, injectBlocks, provideBlok };
684
- export type { AngularBlockRenderContext, BlockNode, BlokAngularConfig, CaretTarget, CreateAngularBlockSpec, InsertPosition, InsertSpec, MoveTarget, PropSchema, PropSchemaEntry, TreeInsertSpec, UseBlocksApi };
751
+ export { BLOK_BLOCK_CONTEXT, BLOK_DEFAULT_CONFIG, BlokContentDirective, BlokEditorComponent, createAngularBlock, injectBlocks, injectBlokReady, provideBlok };
752
+ export type { AngularBlockRenderContext, BlockNode, BlokAngularConfig, BlokReadyScope, CaretTarget, CreateAngularBlockSpec, InjectBlokReadyOptions, InsertPosition, InsertSpec, MoveTarget, PropSchema, PropSchemaEntry, TreeInsertSpec, UseBlocksApi };