@notectl/core 1.0.0 → 1.0.2

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 CHANGED
@@ -52,15 +52,16 @@ npm install @notectl/core
52
52
  ```ts
53
53
  import {
54
54
  createEditor,
55
+ ThemePreset,
55
56
  TextFormattingPlugin,
56
57
  HeadingPlugin,
57
58
  ListPlugin,
58
59
  LinkPlugin,
59
60
  TablePlugin,
60
- ToolbarPlugin,
61
61
  } from '@notectl/core';
62
62
 
63
63
  const editor = await createEditor({
64
+ theme: ThemePreset.Light,
64
65
  toolbar: [
65
66
  [new TextFormattingPlugin({ bold: true, italic: true, underline: true })],
66
67
  [new HeadingPlugin()],
@@ -74,7 +75,7 @@ const editor = await createEditor({
74
75
  document.body.appendChild(editor);
75
76
  ```
76
77
 
77
- That's it. A full-featured editor in 15 lines.
78
+ That's it. A full-featured editor in 16 lines. `ThemePreset.Light` and `ThemePreset.Dark` are available out of the box.
78
79
 
79
80
  <br />
80
81
 
package/dist/index.d.ts CHANGED
@@ -122,6 +122,21 @@ export declare class BlockquotePlugin implements Plugin_2 {
122
122
  private setBlockType;
123
123
  }
124
124
 
125
+ export declare interface BlockTypePickerEntry {
126
+ /** Unique identifier, e.g. 'heading-1', 'footer'. */
127
+ readonly id: string;
128
+ /** Display label shown in the picker, e.g. 'Heading 1'. */
129
+ readonly label: string;
130
+ /** Command to execute when the entry is selected. */
131
+ readonly command: string;
132
+ /** Sort order — lower values appear first. */
133
+ readonly priority: number;
134
+ /** Optional styling for the label in the picker dropdown. */
135
+ readonly style?: PickerEntryStyle;
136
+ /** Returns true when this entry matches the current block type. */
137
+ isActive(state: EditorState): boolean;
138
+ }
139
+
125
140
  export declare interface BoldMark extends Mark {
126
141
  readonly type: MarkTypeName & 'bold';
127
142
  }
@@ -194,6 +209,28 @@ export declare interface CodeBlockConfig {
194
209
  readonly textColor?: string;
195
210
  /** Default header/label text color (overrides --notectl-code-block-header-color). */
196
211
  readonly headerColor?: string;
212
+ /** Customize keyboard bindings for code block actions. */
213
+ readonly keymap?: CodeBlockKeymap;
214
+ }
215
+
216
+ /**
217
+ * Configurable keyboard bindings for CodeBlockPlugin actions.
218
+ * Omit a slot to use the default; set to `null` to disable the binding.
219
+ *
220
+ * Key descriptor format: `'Mod-Enter'`, `'Mod-Shift-M'`, etc.
221
+ * `Mod` resolves to Cmd on macOS, Ctrl on Windows/Linux.
222
+ */
223
+ export declare interface CodeBlockKeymap {
224
+ /**
225
+ * Insert a new paragraph below the code block and move the cursor there.
226
+ * @default 'Mod-Enter'
227
+ */
228
+ readonly insertAfter?: string | null;
229
+ /**
230
+ * Toggle the current block between code block and paragraph.
231
+ * @default 'Mod-Shift-M'
232
+ */
233
+ readonly toggle?: string | null;
197
234
  }
198
235
 
199
236
  export declare class CodeBlockPlugin implements Plugin_2 {
@@ -201,10 +238,12 @@ export declare class CodeBlockPlugin implements Plugin_2 {
201
238
  readonly name = "Code Block";
202
239
  readonly priority = 36;
203
240
  private readonly config;
241
+ private readonly resolvedKeymap;
204
242
  private context;
205
243
  constructor(config?: Partial<CodeBlockConfig>);
206
244
  init(context: PluginContext): void;
207
245
  destroy(): void;
246
+ onStateChange(oldState: EditorState, newState: EditorState, _tr: Transaction): void;
208
247
  decorations(state: EditorState): DecorationSet;
209
248
  private registerNodeSpec;
210
249
  private registerNodeView;
@@ -234,6 +273,21 @@ export declare class CodeBlockPlugin implements Plugin_2 {
234
273
  * Exits to the previous block.
235
274
  */
236
275
  private handleArrowUp;
276
+ /**
277
+ * Handles ArrowRight at the end of a code block.
278
+ * Exits to the next block or creates a paragraph below.
279
+ */
280
+ private handleArrowRight;
281
+ /**
282
+ * Handles ArrowLeft at the start of a code block.
283
+ * Exits to the previous block at end.
284
+ */
285
+ private handleArrowLeft;
286
+ /**
287
+ * Handles Mod+Enter: always creates a paragraph below and moves cursor there.
288
+ */
289
+ private handleModEnter;
290
+ private setBlockFocused;
237
291
  private toggleCodeBlock;
238
292
  private insertCodeBlock;
239
293
  private exitOnDoubleEnter;
@@ -751,6 +805,7 @@ export declare class HeadingPlugin implements Plugin_2 {
751
805
  private registerCommands;
752
806
  private registerKeymaps;
753
807
  private registerInputRules;
808
+ private registerPickerEntries;
754
809
  private registerToolbarItem;
755
810
  private updateComboLabel;
756
811
  private getActiveLabel;
@@ -1286,6 +1341,14 @@ export declare interface NodeSpec<T extends string = string> {
1286
1341
  readonly parseHTML?: readonly ParseRule[];
1287
1342
  /** Tags and attributes this spec needs through DOMPurify sanitization. */
1288
1343
  readonly sanitize?: SanitizeConfig;
1344
+ /**
1345
+ * If provided, the Reconciler groups consecutive blocks with the same
1346
+ * wrapper key into a shared wrapper element. Useful for semantic list
1347
+ * wrappers (`<ul>`, `<ol>`) around `<li>` block elements.
1348
+ */
1349
+ wrapper?(node: Omit<BlockNode, 'attrs'> & {
1350
+ readonly attrs: NodeAttrsFor<T>;
1351
+ }): WrapperSpec;
1289
1352
  }
1290
1353
 
1291
1354
  /** @deprecated Use {@link NodeTypeName} for new code. */
@@ -1413,7 +1476,7 @@ export declare class NotectlEditor extends HTMLElement {
1413
1476
  private emit;
1414
1477
  private onStateChange;
1415
1478
  private updateEmptyState;
1416
- private announceFormatChange;
1479
+ private announceStateChange;
1417
1480
  private replaceState;
1418
1481
  private serializeBlock;
1419
1482
  private serializeInlineContent;
@@ -1462,6 +1525,11 @@ export declare interface PartialTheme {
1462
1525
  readonly tooltip?: Partial<ThemeTooltip>;
1463
1526
  }
1464
1527
 
1528
+ export declare interface PickerEntryStyle {
1529
+ readonly fontSize: string;
1530
+ readonly fontWeight: string;
1531
+ }
1532
+
1465
1533
  declare interface Plugin_2<TConfig extends Record<string, unknown> = Record<string, unknown>> {
1466
1534
  readonly id: string;
1467
1535
  readonly name: string;
@@ -1504,7 +1572,10 @@ export declare interface PluginContext {
1504
1572
  registerToolbarItem(item: ToolbarItem): void;
1505
1573
  registerInlineNodeSpec<T extends string>(spec: InlineNodeSpec<T>): void;
1506
1574
  registerFileHandler(pattern: string, handler: FileHandler): void;
1575
+ registerBlockTypePickerEntry(entry: BlockTypePickerEntry): void;
1507
1576
  getSchemaRegistry(): SchemaRegistry;
1577
+ /** Pushes a screen reader announcement via the editor's aria-live region. */
1578
+ announce(text: string): void;
1508
1579
  }
1509
1580
 
1510
1581
  export declare interface PluginEventBus {
@@ -1573,6 +1644,8 @@ export declare interface PluginManagerInitOptions {
1573
1644
  dispatch(transaction: Transaction): void;
1574
1645
  getContainer(): HTMLElement;
1575
1646
  getPluginContainer(position: 'top' | 'bottom'): HTMLElement;
1647
+ /** Pushes a screen reader announcement via the editor's aria-live region. */
1648
+ announce?(text: string): void;
1576
1649
  /** Called after all plugin init() calls complete, before onReady(). */
1577
1650
  onBeforeReady?(): void | Promise<void>;
1578
1651
  }
@@ -1660,6 +1733,7 @@ export declare class SchemaRegistry {
1660
1733
  private readonly _toolbarItems;
1661
1734
  private readonly _toolbarItemPluginMap;
1662
1735
  private readonly _fileHandlers;
1736
+ private readonly _blockTypePickerEntries;
1663
1737
  registerNodeSpec<T extends string>(spec: NodeSpec<T>): void;
1664
1738
  getNodeSpec(type: string): NodeSpec | undefined;
1665
1739
  removeNodeSpec(type: string): void;
@@ -1690,6 +1764,9 @@ export declare class SchemaRegistry {
1690
1764
  getFileHandlers(): readonly FileHandlerEntry[];
1691
1765
  matchFileHandlers(mimeType: string): FileHandler[];
1692
1766
  removeFileHandler(handler: FileHandler): void;
1767
+ registerBlockTypePickerEntry(entry: BlockTypePickerEntry): void;
1768
+ getBlockTypePickerEntries(): readonly BlockTypePickerEntry[];
1769
+ removeBlockTypePickerEntry(id: string): void;
1693
1770
  /** Returns all NodeSpec parseHTML rules, sorted by priority descending. */
1694
1771
  getBlockParseRules(): readonly {
1695
1772
  readonly rule: ParseRule;
@@ -2126,37 +2203,38 @@ export declare class ToolbarPlugin implements Plugin_2 {
2126
2203
  private context;
2127
2204
  private toolbarElement;
2128
2205
  private buttons;
2129
- private activePopup;
2130
- private closePopupHandler;
2131
2206
  private readonly hiddenItems;
2132
- private tooltipElement;
2133
- private tooltipTimer;
2134
2207
  private readonly layoutConfig;
2208
+ private focusedIndex;
2209
+ private tooltip;
2210
+ private popupController;
2135
2211
  constructor(layoutConfig?: ToolbarLayoutConfig);
2136
2212
  init(context: PluginContext): void;
2137
2213
  onReady(): void;
2138
2214
  destroy(): void;
2139
2215
  onStateChange(_oldState: EditorState, newState: EditorState, _tr: Transaction): void;
2140
2216
  onConfigure(config: PluginConfig): void;
2141
- private createTooltipElement;
2142
- private showTooltip;
2143
- private hideTooltip;
2144
2217
  private createToolbarElement;
2145
2218
  private renderItems;
2219
+ private initRovingTabindex;
2220
+ private setRovingFocus;
2221
+ /** Returns the active element, respecting shadow DOM boundaries. */
2222
+ private getActiveElement;
2223
+ private syncFocusedIndex;
2224
+ private handleToolbarKeydown;
2225
+ /** Activates a toolbar button (shared between mouse click and keyboard). */
2226
+ private activateButton;
2146
2227
  private renderItemsByLayout;
2147
2228
  private renderItemsByPriority;
2148
2229
  private createButton;
2149
- private activePopupButton;
2150
- private togglePopup;
2151
- private closePopup;
2152
- private renderGridPicker;
2153
- private renderDropdown;
2154
2230
  private updateButtonStates;
2155
2231
  }
2156
2232
 
2157
2233
  export declare interface ToolbarServiceAPI {
2158
2234
  /** Re-reads isActive/isEnabled from state and updates all buttons. */
2159
2235
  refresh(): void;
2236
+ /** Closes the currently open popup, if any. */
2237
+ closePopup(): void;
2160
2238
  }
2161
2239
 
2162
2240
  export declare const ToolbarServiceKey: ServiceKey<ToolbarServiceAPI>;
@@ -2229,6 +2307,7 @@ export declare class TransactionBuilder {
2229
2307
  export declare interface TransactionMetadata {
2230
2308
  readonly origin: TransactionOrigin;
2231
2309
  readonly timestamp: number;
2310
+ readonly historyDirection?: 'undo' | 'redo';
2232
2311
  }
2233
2312
 
2234
2313
  export declare type TransactionMiddleware = (tr: Transaction, state: EditorState, next: MiddlewareNext) => void;
@@ -2266,4 +2345,16 @@ export declare function widgetDecoration(blockId: BlockId, offset: number, toDOM
2266
2345
  readonly key?: string;
2267
2346
  }): WidgetDecoration;
2268
2347
 
2348
+ /** Describes a wrapper element that groups consecutive blocks of the same kind. */
2349
+ export declare interface WrapperSpec {
2350
+ /** The HTML tag for the wrapper element (e.g., 'ul', 'ol'). */
2351
+ readonly tag: string;
2352
+ /** A key to group consecutive blocks. Blocks with the same key share a wrapper. */
2353
+ readonly key: string;
2354
+ /** Optional CSS class for the wrapper element. */
2355
+ readonly className?: string;
2356
+ /** Optional attributes for the wrapper element. */
2357
+ readonly attrs?: Readonly<Record<string, string>>;
2358
+ }
2359
+
2269
2360
  export { }