@domternal/vanilla 0.14.0 → 1.0.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 CHANGED
@@ -4,9 +4,10 @@
4
4
  [![MIT License](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/domternal/domternal/blob/main/LICENSE)
5
5
 
6
6
  Framework-free DOM components for the [Domternal](https://domternal.dev) editor.
7
- Each component is a class you instantiate against a host element:
8
- `DomternalEditor`, `DomternalToolbar`, `DomternalBubbleMenu`, `DomternalFloatingMenu`,
9
- `DomternalEmojiPicker`, and `DomternalNotionColorPicker`. Every class extends
7
+ Most are classes you instantiate against a host element: `DomternalEditor`,
8
+ `DomternalToolbar`, `DomternalBubbleMenu`, `DomternalFloatingMenu`, and
9
+ `DomternalEmojiPicker`. `DomternalNotionColorPicker` is the exception: it takes only an
10
+ options object and resolves its own `.dm-editor` host from the editor. Every class extends
10
11
  `EventTarget`, exposes plain getters and mutator methods, dispatches `CustomEvent`s for state
11
12
  changes, and tears down with an idempotent `destroy()`. Use it in Astro, Svelte, Solid,
12
13
  Lit, Web Components, or plain HTML - anywhere without a framework runtime.
@@ -21,8 +22,8 @@ Lit, Web Components, or plain HTML - anywhere without a framework runtime.
21
22
  pnpm add @domternal/core @domternal/theme @domternal/vanilla
22
23
  ```
23
24
 
24
- `@domternal/core` is a peer dependency. `@domternal/theme` supplies the editor styles
25
- (import it once in your app).
25
+ `@domternal/core` (>=1.0.0) is a peer dependency. `@domternal/theme` supplies the editor
26
+ styles (import it once in your app).
26
27
 
27
28
  ## Usage
28
29
 
@@ -70,6 +71,24 @@ The matching mount points:
70
71
  > SSR. Module-scope imports stay SSR-safe, so gate instantiation behind a client-side
71
72
  > entry point (e.g. an Astro `<script>` block or `client:only`).
72
73
 
74
+ ## Options
75
+
76
+ `DomternalEditorOptions`, the second constructor argument:
77
+
78
+ | Option | Type | Default | Description |
79
+ |---|---|---|---|
80
+ | `extensions` | `AnyExtension[]` | `[]` | Extensions merged on top of `DEFAULT_EXTENSIONS`. |
81
+ | `history` | `boolean` | `true` | Whether the built-in History extension is loaded. Turn it off when an extension brings its own undo. |
82
+ | `content` | `Content` | `''` | Initial content, HTML string or JSON. |
83
+ | `editable` | `boolean` | `true` | Whether the editor is editable. |
84
+ | `preset` | `'classic' \| 'notion'` | `'classic'` | `'notion'` paints `dm-notion-mode` on the `.dm-editor` host and switches preset-aware extensions to their Notion behavior. Create-time only. |
85
+ | `autofocus` | `FocusPosition` | `false` | Where to place the caret on mount. |
86
+ | `outputFormat` | `'html' \| 'json'` | `'html'` | Format hint for host frameworks comparing controlled content. Does not change editor behavior. |
87
+
88
+ `onCreate`, `onUpdate`, `onSelectionChange`, `onFocus`, `onBlur`, and `onDestroy` callbacks are
89
+ accepted alongside them, and the same moments are dispatched on the instance as `create`,
90
+ `update`, `selectionchange`, `focus`, `blur`, and `destroy` `CustomEvent`s.
91
+
73
92
  ## Exports
74
93
 
75
94
  - `DomternalEditor` / `DomternalEditorOptions` - wraps core's `Editor`, plus
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { PluginKey, IconSet, Editor, AnyExtension, Content, FocusPosition, JSONContent, ToolbarController, ToolbarLayoutEntry, ToolbarButton, ToolbarDropdown, BubbleMenuOptions, FloatingMenuController, FloatingMenuOptions, FloatingMenuItemsOverride, FloatingMenuKeymap } from '@domternal/core';
1
+ import { PluginKey, IconSet, AnyExtension, Editor, Content, EditorPreset, FocusPosition, JSONContent, ToolbarController, ToolbarLayoutEntry, ToolbarButton, ToolbarDropdown, BubbleMenuOptions, BubbleContexts, FloatingMenuController, FloatingMenuOptions, FloatingMenuItemsOverride, FloatingMenuKeymap } from '@domternal/core';
2
+ export { BubbleMenuItem, BubbleMenuSeparator, BubbleItemMaps as ItemMaps, ResolvedPosShape, SelectionShape, buildBubbleItemMaps as buildItemMaps, detectBubbleContext as detectContext, filterBubbleItemsBySchema as filterBySchema, getBubbleFormatItems as getFormatItems, isInsideTableCell, resolveBubbleNames as resolveNames } from '@domternal/core';
2
3
 
3
4
  /**
4
5
  * SSR-safe environment check.
@@ -200,6 +201,12 @@ interface DomternalEditorOptions {
200
201
  content?: Content;
201
202
  /** Whether the editor is editable. @default true */
202
203
  editable?: boolean;
204
+ /**
205
+ * Editing experience preset. `'notion'` paints `dm-notion-mode` on the
206
+ * `.dm-editor` host and switches preset-aware extensions to their Notion
207
+ * behavior, replacing the hand-written class. Create-time only.
208
+ */
209
+ preset?: EditorPreset;
203
210
  /** Where to autofocus on mount. @default false */
204
211
  autofocus?: FocusPosition;
205
212
  /**
@@ -434,85 +441,6 @@ declare function getComputedStyleAtCursor(editor: Editor, prop: string): string
434
441
  */
435
442
  declare function getInlineStyleAtCursor(editor: Editor, prop: string): string | null;
436
443
 
437
- interface ResolvedPosShape {
438
- parent: {
439
- type: {
440
- name: string;
441
- spec: {
442
- marks?: string;
443
- };
444
- };
445
- };
446
- depth: number;
447
- node: (depth: number) => {
448
- type: {
449
- name: string;
450
- };
451
- };
452
- }
453
- interface SelectionShape {
454
- empty: boolean;
455
- $from: ResolvedPosShape;
456
- $to: ResolvedPosShape;
457
- node?: {
458
- type: {
459
- name: string;
460
- };
461
- };
462
- }
463
- interface BubbleMenuSeparator {
464
- type: 'separator';
465
- name: string;
466
- }
467
- type BubbleMenuItem = ToolbarButton | ToolbarDropdown | BubbleMenuSeparator;
468
- interface ItemMaps {
469
- itemMap: Map<string, ToolbarButton>;
470
- dropdownMap: Map<string, ToolbarDropdown>;
471
- /** Bubble defaults indexed by context name (e.g. 'text', 'codeBlock'). */
472
- bubbleDefaults: Map<string, BubbleMenuItem[]>;
473
- }
474
- /**
475
- * Walks `editor.toolbarItems` and indexes them by name. Dropdowns are kept
476
- * separately so the bubble menu can resolve them by name (e.g. text-align).
477
- */
478
- declare function buildItemMaps(editor: Editor): ItemMaps;
479
- /**
480
- * Resolve a name array to BubbleMenuItems via the item/dropdown maps.
481
- * Dropdowns take priority over buttons sharing the same name. Pipe `|`
482
- * tokens become separator entries.
483
- */
484
- declare function resolveNames(names: string[], itemMap: Map<string, ToolbarButton>, dropdownMap: Map<string, ToolbarDropdown>): BubbleMenuItem[];
485
- /**
486
- * All `format`-group buttons sorted by priority (used by `context: true`
487
- * shorthand to show "all format marks for this context").
488
- */
489
- declare function getFormatItems(itemMap: Map<string, ToolbarButton>): ToolbarButton[];
490
- /**
491
- * Determine the active bubble-menu context based on the selection. Returns
492
- * `null` when no context matches (menu should not show).
493
- *
494
- * Resolution order:
495
- * 1. CellSelection (`$anchorCell`) - no menu inside table cell selections
496
- * 2. NodeSelection (image, HR, etc.) - return the node's type name
497
- * 3. Empty selection - no context (caret-only)
498
- * 4. Inside a table cell - return 'table' (when from/to share a cell)
499
- * 5. `$from.parent.type.name` if listed in contexts
500
- * 6. 'text' if the parent allows marks
501
- */
502
- declare function detectContext(selection: SelectionShape, ctxs: Record<string, string[] | true | null>): string | null;
503
- /**
504
- * Filter items by what the schema actually allows in the given context.
505
- * E.g. inside a `codeBlock` node, marks like Bold/Italic aren't permitted.
506
- *
507
- * Pass-through for 'text' and 'table' contexts (schema check would be
508
- * lossy there because marks are allowed but some items still apply).
509
- */
510
- declare function filterBySchema(editor: Editor, contextName: string, schemaItems: ToolbarButton[]): ToolbarButton[];
511
- /**
512
- * Detect whether `$pos` is inside a table cell (cell or header).
513
- */
514
- declare function isInsideTableCell($pos: ResolvedPosShape): boolean;
515
-
516
444
  /**
517
445
  * Live state for the bubble-menu trailing buttons.
518
446
  *
@@ -570,7 +498,7 @@ interface DomternalBubbleMenuOptions extends CustomContentOption {
570
498
  * to item name list, `true` (show all format items), or `null` (no menu for
571
499
  * this context). Defaults to `defaultBubbleContexts(editor)`.
572
500
  */
573
- contexts?: Record<string, string[] | true | null>;
501
+ contexts?: BubbleContexts;
574
502
  /** Custom icon overrides. Falls back to default Phosphor icons for unmapped keys. */
575
503
  icons?: IconSet;
576
504
  }
@@ -584,14 +512,13 @@ interface DomternalBubbleMenuOptions extends CustomContentOption {
584
512
  * "..." for block context menu) are rendered automatically when the
585
513
  * corresponding extensions are loaded.
586
514
  *
587
- * Re-renders are batched via `requestAnimationFrame`. DOM is rebuilt on every
588
- * transaction because the item list changes with context (selection moves
589
- * between text and code-block, for example).
515
+ * Re-renders are batched via `requestAnimationFrame`. The structure is rebuilt
516
+ * only when the item list changes; a state-only render updates the nodes on
517
+ * screen, so a press that outlives a transaction still produces a click.
590
518
  *
591
- * **Stable identity convention.** Trigger buttons (including the "A" and "..."
592
- * trailing triggers and dropdown triggers) are DESTROYED and RECREATED on
593
- * every transaction. Consumers that store a reference to a trigger element
594
- * (e.g. as a popover anchor) should:
519
+ * **Stable identity convention.** A trigger survives a state-only render but
520
+ * NOT an item-list change, so consumers holding a reference to one (e.g. as a
521
+ * popover anchor) should still:
595
522
  * - Either listen for `selectionUpdate` / `transaction` and re-resolve the
596
523
  * anchor via `host.querySelector('.dm-ncp-trigger')` on demand
597
524
  * - Or match the trigger by class + container (`closest('.dm-bubble-menu')`)
@@ -661,7 +588,7 @@ declare class DomternalBubbleMenu extends EventTarget {
661
588
  * plugin at construction; this only changes WHICH items render once the
662
589
  * menu is visible.
663
590
  */
664
- setContexts(contexts: Record<string, string[] | true | null> | undefined): void;
591
+ setContexts(contexts: BubbleContexts | undefined): void;
665
592
  /** Replace the icon set. `undefined` restores default Phosphor icons. */
666
593
  setIcons(icons: IconSet | undefined): void;
667
594
  /** Close any open dropdown (text-align). No-op if nothing is open. */
@@ -873,4 +800,4 @@ declare class DomternalEmojiPicker extends EventTarget {
873
800
  destroy(): void;
874
801
  }
875
802
 
876
- export { type BubbleMenuItem, type BubbleMenuSeparator, type BubbleMenuTrailingState, type CustomContentOption, DEFAULT_EXTENSIONS, DROPDOWN_CARET, DomternalBubbleMenu, type DomternalBubbleMenuOptions, DomternalEditor, type DomternalEditorOptions, DomternalEmojiPicker, type DomternalEmojiPickerOptions, DomternalFloatingMenu, type DomternalFloatingMenuOptions, DomternalNotionColorPicker, type DomternalNotionColorPickerOptions, DomternalToolbar, type DomternalToolbarOptions, type EmojiPickerItem, INITIAL_TRAILING_STATE, type IconCache, type ItemMaps, type ResolvedPosShape, type SelectionShape, assertBrowser, buildItemMaps, computeTrailingState, createIconCache, createPluginKey, detectContext, filterBySchema, getComputedStyleAtCursor, getFormatItems, getInlineStyleAtCursor, getTooltip, isBrowser, isInsideTableCell, renderIconInto, resolveIcon, resolveNames, subscribe };
803
+ export { type BubbleMenuTrailingState, type CustomContentOption, DEFAULT_EXTENSIONS, DROPDOWN_CARET, DomternalBubbleMenu, type DomternalBubbleMenuOptions, DomternalEditor, type DomternalEditorOptions, DomternalEmojiPicker, type DomternalEmojiPickerOptions, DomternalFloatingMenu, type DomternalFloatingMenuOptions, DomternalNotionColorPicker, type DomternalNotionColorPickerOptions, DomternalToolbar, type DomternalToolbarOptions, type EmojiPickerItem, INITIAL_TRAILING_STATE, type IconCache, assertBrowser, computeTrailingState, createIconCache, createPluginKey, getComputedStyleAtCursor, getInlineStyleAtCursor, getTooltip, isBrowser, renderIconInto, resolveIcon, subscribe };