@domternal/angular 0.6.1 → 0.7.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/README.md +12 -10
- package/dist/README.md +12 -10
- package/dist/fesm2022/domternal-angular.mjs +1190 -84
- package/dist/fesm2022/domternal-angular.mjs.map +1 -1
- package/dist/types/domternal-angular.d.ts +164 -10
- package/package.json +5 -3
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
2
|
import { OnDestroy, ElementRef } from '@angular/core';
|
|
3
3
|
import { ControlValueAccessor } from '@angular/forms';
|
|
4
|
-
import
|
|
4
|
+
import * as _domternal_core from '@domternal/core';
|
|
5
|
+
import { AnyExtension, Content, FocusPosition, Editor, JSONContent, IconSet, ToolbarLayoutEntry, ToolbarGroup, ToolbarDropdown, ToolbarButton, ToolbarItem, FloatingMenuItemsOverride, FloatingMenuItem } from '@domternal/core';
|
|
5
6
|
export { AnyExtension, Content, Editor, FocusPosition, JSONContent } from '@domternal/core';
|
|
6
7
|
import { SafeHtml } from '@angular/platform-browser';
|
|
7
8
|
import * as prosemirror_state from 'prosemirror-state';
|
|
8
9
|
import * as prosemirror_view from 'prosemirror-view';
|
|
10
|
+
import { FloatingMenuKeymap } from '@domternal/extension-block-menu';
|
|
9
11
|
|
|
10
12
|
declare const DEFAULT_EXTENSIONS: AnyExtension[];
|
|
11
13
|
declare class DomternalEditorComponent implements ControlValueAccessor, OnDestroy {
|
|
@@ -77,7 +79,7 @@ declare class DomternalToolbarComponent implements OnDestroy {
|
|
|
77
79
|
private ngZone;
|
|
78
80
|
private elRef;
|
|
79
81
|
private sanitizer;
|
|
80
|
-
/** SafeHtml cache
|
|
82
|
+
/** SafeHtml cache - same reference returned for same key, prevents DOM churn */
|
|
81
83
|
private htmlCache;
|
|
82
84
|
private readonly dropdownCaret;
|
|
83
85
|
constructor();
|
|
@@ -89,7 +91,7 @@ declare class DomternalToolbarComponent implements OnDestroy {
|
|
|
89
91
|
getDropdownTriggerHtml(dropdown: ToolbarDropdown): SafeHtml;
|
|
90
92
|
/**
|
|
91
93
|
* Returns 'true' when an emitEvent button's panel is open, null otherwise.
|
|
92
|
-
* Maps to [attr.aria-expanded]
|
|
94
|
+
* Maps to [attr.aria-expanded] - null removes the attribute entirely.
|
|
93
95
|
*/
|
|
94
96
|
getAriaExpanded(item: ToolbarButton): string | null;
|
|
95
97
|
getFlatIndex(name: string): number;
|
|
@@ -112,7 +114,7 @@ declare class DomternalToolbarComponent implements OnDestroy {
|
|
|
112
114
|
private destroyController;
|
|
113
115
|
private syncState;
|
|
114
116
|
private getComputedStyleAtCursor;
|
|
115
|
-
/** Read only inline style
|
|
117
|
+
/** Read only inline style - no computed fallback (used for font-family). */
|
|
116
118
|
private getInlineStyleAtCursor;
|
|
117
119
|
private focusCurrentButton;
|
|
118
120
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DomternalToolbarComponent, never>;
|
|
@@ -123,7 +125,7 @@ interface BubbleMenuSeparator {
|
|
|
123
125
|
type: 'separator';
|
|
124
126
|
name: string;
|
|
125
127
|
}
|
|
126
|
-
type BubbleMenuItem = ToolbarButton | BubbleMenuSeparator;
|
|
128
|
+
type BubbleMenuItem = ToolbarButton | ToolbarDropdown | BubbleMenuSeparator;
|
|
127
129
|
declare class DomternalBubbleMenuComponent implements OnDestroy {
|
|
128
130
|
readonly editor: _angular_core.InputSignal<Editor>;
|
|
129
131
|
readonly shouldShow: _angular_core.InputSignal<(props: {
|
|
@@ -140,25 +142,72 @@ declare class DomternalBubbleMenuComponent implements OnDestroy {
|
|
|
140
142
|
readonly items: _angular_core.InputSignal<string[]>;
|
|
141
143
|
/** Context-aware: map context names to item arrays, `true` for all valid items, or `null` to disable */
|
|
142
144
|
readonly contexts: _angular_core.InputSignal<Record<string, true | string[]>>;
|
|
143
|
-
/**
|
|
145
|
+
/**
|
|
146
|
+
* Custom icon overrides. Falls back to default Phosphor icons for unmapped keys.
|
|
147
|
+
* For nullable bindings, use `iconsSignal() ?? {}` to satisfy strict template checks.
|
|
148
|
+
*/
|
|
149
|
+
readonly icons: _angular_core.InputSignal<IconSet>;
|
|
150
|
+
/**
|
|
151
|
+
* Returns the effective contexts map: the explicit `contexts` input
|
|
152
|
+
* when provided, the standard default when neither `contexts` nor
|
|
153
|
+
* `items` is set, or `undefined` (items-mode) when only `items` is set.
|
|
154
|
+
* The standard default is richer when the editor sits inside
|
|
155
|
+
* `.dm-notion-mode`.
|
|
156
|
+
*/
|
|
157
|
+
private resolveContexts;
|
|
158
|
+
/** Internal - updated on transactions. Not meant to be set from outside. */
|
|
144
159
|
readonly resolvedItems: _angular_core.WritableSignal<BubbleMenuItem[]>;
|
|
160
|
+
/** Internal - true when the BlockContextMenu extension is loaded; toggles the "..." trailing button. */
|
|
161
|
+
readonly showBlockMenuButton: _angular_core.WritableSignal<boolean>;
|
|
162
|
+
/** Internal - true when the selection spans more than one top-level block; the "..." trigger is disabled in that case because block-level commands have no unambiguous target. */
|
|
163
|
+
readonly blockMenuButtonDisabled: _angular_core.WritableSignal<boolean>;
|
|
164
|
+
/** Internal - true when the current selection is a NodeSelection (image, HR). The text-color and block-context triggers are hidden in that case: a node has no inline text to color and its bubble menu already exposes node-specific actions. */
|
|
165
|
+
readonly isNodeSelection: _angular_core.WritableSignal<boolean>;
|
|
166
|
+
/** Internal - true when the NotionColorPicker extension is loaded; toggles the "A" color trigger. */
|
|
167
|
+
readonly showColorPickerButton: _angular_core.WritableSignal<boolean>;
|
|
168
|
+
/** Current text color CSS variable expression for the trigger glyph (null = default). */
|
|
169
|
+
readonly currentTextColorVar: _angular_core.WritableSignal<string>;
|
|
170
|
+
/** Current background color CSS variable expression for the trigger underline (null = transparent). */
|
|
171
|
+
readonly currentBgColorVar: _angular_core.WritableSignal<string>;
|
|
172
|
+
/** Internal - true when the selection has any token-based text or background color applied. */
|
|
173
|
+
readonly hasAnyColor: _angular_core.WritableSignal<boolean>;
|
|
145
174
|
private menuEl;
|
|
146
175
|
private pluginKey;
|
|
147
176
|
private sanitizer;
|
|
148
177
|
private ngZone;
|
|
149
178
|
private activeVersion;
|
|
150
179
|
private itemMap;
|
|
180
|
+
private dropdownMap;
|
|
151
181
|
private activeMap;
|
|
152
182
|
private disabledMap;
|
|
153
183
|
private htmlCache;
|
|
154
184
|
private bubbleDefaults;
|
|
155
185
|
private transactionHandler;
|
|
186
|
+
readonly openDropdown: _angular_core.WritableSignal<string>;
|
|
187
|
+
private dropdownCleanupFloating;
|
|
188
|
+
private dropdownOutsideHandler;
|
|
189
|
+
private dropdownKeydownHandler;
|
|
190
|
+
private dropdownDismissHandler;
|
|
191
|
+
private readonly dropdownCaret;
|
|
156
192
|
constructor();
|
|
157
193
|
ngOnDestroy(): void;
|
|
158
194
|
isItemActive(item: ToolbarButton): boolean;
|
|
159
195
|
isItemDisabled(item: ToolbarButton): boolean;
|
|
160
196
|
getCachedIcon(name: string): SafeHtml;
|
|
161
|
-
executeCommand(item: ToolbarButton): void;
|
|
197
|
+
executeCommand(item: ToolbarButton, event?: Event): void;
|
|
198
|
+
/**
|
|
199
|
+
* Emit the `notionColorOpen` event with the trigger button as the anchor.
|
|
200
|
+
* The framework popover component (DomternalNotionColorPickerComponent)
|
|
201
|
+
* listens for this event and positions itself against the anchor.
|
|
202
|
+
*/
|
|
203
|
+
openColorPicker(anchor: HTMLElement): void;
|
|
204
|
+
/**
|
|
205
|
+
* Open the BlockContextMenu against the cursor's containing block. Skips
|
|
206
|
+
* the textblock for nested cases (cursor in `listItem > paragraph` targets
|
|
207
|
+
* the listItem, not the paragraph) so Delete / Turn into operate on the
|
|
208
|
+
* "visual block" the user is editing.
|
|
209
|
+
*/
|
|
210
|
+
openBlockContextMenu(anchor: HTMLElement): void;
|
|
162
211
|
private buildItemMap;
|
|
163
212
|
private resolveNames;
|
|
164
213
|
private getFormatItems;
|
|
@@ -168,12 +217,48 @@ declare class DomternalBubbleMenuComponent implements OnDestroy {
|
|
|
168
217
|
private filterBySchema;
|
|
169
218
|
private buildBubbleDefaults;
|
|
170
219
|
private setupItemTracking;
|
|
220
|
+
/**
|
|
221
|
+
* Refresh state for the optional trailing buttons (A color trigger,
|
|
222
|
+
* "..." block menu) and the isNodeSelection flag. Called from both
|
|
223
|
+
* setupItemTracking init and the per-transaction handler so the two
|
|
224
|
+
* paths stay in sync.
|
|
225
|
+
*/
|
|
226
|
+
private syncTrailingButtonsState;
|
|
227
|
+
/**
|
|
228
|
+
* Disable the "..." trigger when the selection spans more than one
|
|
229
|
+
* top-level block. The block context menu targets the block at $from, so
|
|
230
|
+
* a multi-block selection has no unambiguous target.
|
|
231
|
+
*/
|
|
232
|
+
private syncBlockMenuButtonState;
|
|
233
|
+
/**
|
|
234
|
+
* Update the trigger's indicator colors to mirror the current selection.
|
|
235
|
+
* Used by the "A" button so the underline matches whatever the user has
|
|
236
|
+
* applied at the cursor (Notion-style live preview).
|
|
237
|
+
*/
|
|
238
|
+
private syncColorTriggerState;
|
|
171
239
|
private updateContextItems;
|
|
172
240
|
private updateStates;
|
|
241
|
+
asButton(item: BubbleMenuItem): ToolbarButton;
|
|
242
|
+
asDropdown(item: BubbleMenuItem): ToolbarDropdown;
|
|
243
|
+
isDropdownActive(dropdown: ToolbarDropdown): boolean;
|
|
244
|
+
/** Trigger HTML: swap icon to the active child when `dynamicIcon` is set. */
|
|
245
|
+
getDropdownTriggerHtml(dropdown: ToolbarDropdown): SafeHtml;
|
|
246
|
+
getCachedItemContent(iconName: string, label: string): SafeHtml;
|
|
247
|
+
isSubItemActive(name: string): boolean;
|
|
248
|
+
onDropdownToggle(dropdown: ToolbarDropdown, event?: MouseEvent): void;
|
|
249
|
+
onDropdownItemClick(item: ToolbarButton): void;
|
|
250
|
+
private cleanupDropdown;
|
|
173
251
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DomternalBubbleMenuComponent, never>;
|
|
174
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DomternalBubbleMenuComponent, "domternal-bubble-menu", never, { "editor": { "alias": "editor"; "required": true; "isSignal": true; }; "shouldShow": { "alias": "shouldShow"; "required": false; "isSignal": true; }; "placement": { "alias": "placement"; "required": false; "isSignal": true; }; "offset": { "alias": "offset"; "required": false; "isSignal": true; }; "updateDelay": { "alias": "updateDelay"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": false; "isSignal": true; }; "contexts": { "alias": "contexts"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
252
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DomternalBubbleMenuComponent, "domternal-bubble-menu", never, { "editor": { "alias": "editor"; "required": true; "isSignal": true; }; "shouldShow": { "alias": "shouldShow"; "required": false; "isSignal": true; }; "placement": { "alias": "placement"; "required": false; "isSignal": true; }; "offset": { "alias": "offset"; "required": false; "isSignal": true; }; "updateDelay": { "alias": "updateDelay"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": false; "isSignal": true; }; "contexts": { "alias": "contexts"; "required": false; "isSignal": true; }; "icons": { "alias": "icons"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
175
253
|
}
|
|
176
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Block-insert floating menu for Angular.
|
|
257
|
+
*
|
|
258
|
+
* Renders defaults collected from the editor's extensions via
|
|
259
|
+
* `addFloatingMenuItems()`; use `items` to override the list and `icons`
|
|
260
|
+
* to swap the icon set.
|
|
261
|
+
*/
|
|
177
262
|
declare class DomternalFloatingMenuComponent implements OnDestroy {
|
|
178
263
|
readonly editor: _angular_core.InputSignal<Editor>;
|
|
179
264
|
readonly shouldShow: _angular_core.InputSignal<(props: {
|
|
@@ -182,12 +267,38 @@ declare class DomternalFloatingMenuComponent implements OnDestroy {
|
|
|
182
267
|
state: prosemirror_state.EditorState;
|
|
183
268
|
}) => boolean>;
|
|
184
269
|
readonly offset: _angular_core.InputSignal<number>;
|
|
270
|
+
readonly items: _angular_core.InputSignal<FloatingMenuItemsOverride>;
|
|
271
|
+
readonly keymap: _angular_core.InputSignal<FloatingMenuKeymap>;
|
|
272
|
+
readonly icons: _angular_core.InputSignal<IconSet>;
|
|
273
|
+
/**
|
|
274
|
+
* When true, the menu does NOT auto-show on every empty paragraph;
|
|
275
|
+
* it only opens when the BlockHandle `+` button (or any caller of
|
|
276
|
+
* `showFloatingMenu`) explicitly triggers it. Notion-style behaviour
|
|
277
|
+
* - empty rows show a placeholder, the slash menu is the keyboard
|
|
278
|
+
* trigger, the `+` button is the gutter trigger.
|
|
279
|
+
* @default false
|
|
280
|
+
*/
|
|
281
|
+
readonly requireExplicitTrigger: _angular_core.InputSignal<boolean>;
|
|
185
282
|
private menuEl;
|
|
283
|
+
private ngZone;
|
|
284
|
+
private sanitizer;
|
|
186
285
|
private pluginKey;
|
|
286
|
+
private controller;
|
|
287
|
+
private version;
|
|
288
|
+
private iconCache;
|
|
289
|
+
readonly groups: _angular_core.Signal<_domternal_core.FloatingMenuGroup[]>;
|
|
290
|
+
private flatNames;
|
|
291
|
+
private focusedIndex;
|
|
187
292
|
constructor();
|
|
188
293
|
ngOnDestroy(): void;
|
|
294
|
+
flatIndexOf(name: string): number;
|
|
295
|
+
tabIndexFor(name: string): 0 | -1;
|
|
296
|
+
isItemDisabled(item: FloatingMenuItem): boolean;
|
|
297
|
+
iconHtml(name?: string): SafeHtml | null;
|
|
298
|
+
onItemClick(item: FloatingMenuItem): void;
|
|
299
|
+
onKeyDown(e: KeyboardEvent): void;
|
|
189
300
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DomternalFloatingMenuComponent, never>;
|
|
190
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DomternalFloatingMenuComponent, "domternal-floating-menu", never, { "editor": { "alias": "editor"; "required": true; "isSignal": true; }; "shouldShow": { "alias": "shouldShow"; "required": false; "isSignal": true; }; "offset": { "alias": "offset"; "required": false; "isSignal": true; }; }, {}, never,
|
|
301
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DomternalFloatingMenuComponent, "domternal-floating-menu", never, { "editor": { "alias": "editor"; "required": true; "isSignal": true; }; "shouldShow": { "alias": "shouldShow"; "required": false; "isSignal": true; }; "offset": { "alias": "offset"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": false; "isSignal": true; }; "keymap": { "alias": "keymap"; "required": false; "isSignal": true; }; "icons": { "alias": "icons"; "required": false; "isSignal": true; }; "requireExplicitTrigger": { "alias": "requireExplicitTrigger"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
191
302
|
}
|
|
192
303
|
|
|
193
304
|
interface EmojiPickerItem {
|
|
@@ -233,5 +344,48 @@ declare class DomternalEmojiPickerComponent implements OnDestroy {
|
|
|
233
344
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DomternalEmojiPickerComponent, "domternal-emoji-picker", never, { "editor": { "alias": "editor"; "required": true; "isSignal": true; }; "emojis": { "alias": "emojis"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
234
345
|
}
|
|
235
346
|
|
|
236
|
-
|
|
347
|
+
declare class DomternalNotionColorPickerComponent implements OnDestroy {
|
|
348
|
+
readonly editor: _angular_core.InputSignal<Editor>;
|
|
349
|
+
readonly isOpen: _angular_core.WritableSignal<boolean>;
|
|
350
|
+
readonly currentTextToken: _angular_core.WritableSignal<string>;
|
|
351
|
+
readonly currentBgToken: _angular_core.WritableSignal<string>;
|
|
352
|
+
readonly palette: _angular_core.WritableSignal<string[]>;
|
|
353
|
+
private anchorEl;
|
|
354
|
+
private panelEl;
|
|
355
|
+
private ngZone;
|
|
356
|
+
private elRef;
|
|
357
|
+
private eventHandler;
|
|
358
|
+
private clickOutsideHandler;
|
|
359
|
+
private keydownHandler;
|
|
360
|
+
private selectionHandler;
|
|
361
|
+
private cleanupFloating;
|
|
362
|
+
constructor();
|
|
363
|
+
ngOnDestroy(): void;
|
|
364
|
+
tokenLabel(token: string): string;
|
|
365
|
+
applyText(token: string | null): void;
|
|
366
|
+
applyBg(token: string | null): void;
|
|
367
|
+
/**
|
|
368
|
+
* Arrow-key navigation across the 5-column swatch grids. Arrows move
|
|
369
|
+
* within and across rows, Home/End jump to grid boundaries, Tab leaves
|
|
370
|
+
* the picker (browser default), Enter/Space activates the focused swatch.
|
|
371
|
+
* Focus moves sequentially through Text color → Background color so
|
|
372
|
+
* keyboard users can reach any swatch without re-grabbing Tab.
|
|
373
|
+
*/
|
|
374
|
+
onPanelKeydown(event: KeyboardEvent): void;
|
|
375
|
+
close(opts?: {
|
|
376
|
+
refocus?: boolean;
|
|
377
|
+
}): void;
|
|
378
|
+
private setupEventListener;
|
|
379
|
+
private addGlobalListeners;
|
|
380
|
+
private removeGlobalListeners;
|
|
381
|
+
private syncFromSelection;
|
|
382
|
+
private readPalette;
|
|
383
|
+
private getStorage;
|
|
384
|
+
private setStorageOpen;
|
|
385
|
+
private cleanup;
|
|
386
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DomternalNotionColorPickerComponent, never>;
|
|
387
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DomternalNotionColorPickerComponent, "domternal-notion-color-picker", never, { "editor": { "alias": "editor"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export { DEFAULT_EXTENSIONS, DomternalBubbleMenuComponent, DomternalEditorComponent, DomternalEmojiPickerComponent, DomternalFloatingMenuComponent, DomternalNotionColorPickerComponent, DomternalToolbarComponent };
|
|
237
391
|
export type { EmojiPickerItem };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@domternal/angular",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Angular components for Domternal editor",
|
|
5
5
|
"author": "https://github.com/ThomasNowHere",
|
|
6
6
|
"license": "MIT",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"peerDependencies": {
|
|
17
17
|
"@angular/core": ">=17.1.0",
|
|
18
18
|
"@angular/forms": ">=17.1.0",
|
|
19
|
-
"@domternal/core": ">=0.
|
|
19
|
+
"@domternal/core": ">=0.7.0",
|
|
20
|
+
"@domternal/extension-block-menu": ">=0.7.0"
|
|
20
21
|
},
|
|
21
22
|
"files": [
|
|
22
23
|
"dist"
|
|
@@ -41,6 +42,7 @@
|
|
|
41
42
|
},
|
|
42
43
|
"homepage": "https://domternal.dev",
|
|
43
44
|
"scripts": {
|
|
44
|
-
"build": "ng-packagr -p ng-package.json"
|
|
45
|
+
"build": "ng-packagr -p ng-package.json",
|
|
46
|
+
"lint": "eslint src"
|
|
45
47
|
}
|
|
46
48
|
}
|