@mdaemon/html-editor 1.5.0 → 1.6.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
@@ -95,8 +95,8 @@ const editor = new HTMLEditor(container, {
95
95
  | `fontSize_sizes` | string | - | CKEditor alias for `font_size_formats` |
96
96
  | `block_formats` | string | 'Paragraph=p;Heading 1=h1;…' | Block-format dropdown definitions (`blocks` button) |
97
97
  | `style_formats` | StyleFormat[] | *(subset)* | Named styles for the Styles dropdown (`styles` button) |
98
- | `fontName` | string | - | Default font family |
99
- | `fontSize` | string | - | Default font size |
98
+ | `fontName` | string | `arial, helvetica, sans-serif` | Default font family, inlined on every block element (see [Font Family & Size](#font-family--size)) |
99
+ | `fontSize` | string | `12pt` | Default font size, inlined on every paragraph (see [Font Family & Size](#font-family--size)) |
100
100
  | `directionality` | 'ltr' \| 'rtl' | 'ltr' | Text direction |
101
101
  | `language` | string | 'en' | UI language code (built-in translations for 31 languages) |
102
102
  | `height` | string \| number | 300 | Editor height (fixed) |
@@ -402,6 +402,48 @@ Tables are resizable by dragging column borders.
402
402
 
403
403
  > Note: block elements map to headings/paragraph, `color`/`background-color` map to the editor's text-color/highlight marks, and `classes` apply a CSS class to the selection. Arbitrary element wrapping from CKEditor's stylesSet (e.g. `big`, `tt`, `cite`) is not supported by the underlying TipTap schema.
404
404
 
405
+ ## Font Family & Size
406
+
407
+ The editor inlines a **default font directly on the block elements** of the
408
+ exported HTML so content keeps its font when rendered outside the editor (for
409
+ example, an email body opened in another client that doesn't load the editor's
410
+ CSS). Set the base font with `fontName` / `fontSize`:
411
+
412
+ ```typescript
413
+ const editor = new HTMLEditor(container, {
414
+ fontName: 'Georgia, serif',
415
+ fontSize: '14pt',
416
+ });
417
+ ```
418
+
419
+ With the config above, `getContent()` produces blocks that carry the font inline:
420
+
421
+ ```html
422
+ <p style="font-family: Georgia, serif; font-size: 14pt;">Hello</p>
423
+ ```
424
+
425
+ Defaults when the options are omitted: `arial, helvetica, sans-serif` and `12pt`.
426
+
427
+ - `font-family` is inlined on paragraphs **and** headings.
428
+ - `font-size` is inlined on paragraphs only — headings keep their level-based
429
+ sizing (`h1` = 2em, `h2` = 1.5em, …), which a forced default would otherwise
430
+ clobber.
431
+
432
+ **Per-selection changes still work.** Selecting text and picking a font or size
433
+ from the `fontfamily` / `fontsize` toolbar dropdowns (or `execCommand('fontname', …)`
434
+ / `execCommand('fontsize', …)`) produces an inline `<span>` that overrides the
435
+ block default for just that text — so a single paragraph can mix fonts and sizes:
436
+
437
+ ```html
438
+ <p style="font-family: Georgia, serif; font-size: 14pt;">
439
+ this is <span style="font-size: 24pt;">A BIG font</span>, and this is a small font
440
+ </p>
441
+ ```
442
+
443
+ This is handled by the exported `BlockFontStyle` extension (block defaults) layered
444
+ with the inline `FontSize` mark and TipTap's `FontFamily` mark (per-selection
445
+ overrides).
446
+
405
447
  ## Read-Only Mode
406
448
 
407
449
  Start the editor read-only with `readonly: true`, or toggle it at runtime. Read-only mode disables editing and dims/blocks the toolbar.
package/dist/index.d.ts CHANGED
@@ -33,6 +33,19 @@ export declare interface AnchorOptions {
33
33
  /** List of all supported locale codes */
34
34
  export declare const availableLocales: string[];
35
35
 
36
+ export declare const BlockFontStyle: Extension<BlockFontStyleOptions, any>;
37
+
38
+ export declare interface BlockFontStyleOptions {
39
+ /** Node types that receive the default font-family. */
40
+ fontFamilyTypes: string[];
41
+ /** Node types that receive the default font-size. */
42
+ fontSizeTypes: string[];
43
+ /** Default font-family inlined on every matching block. */
44
+ defaultFontFamily: string;
45
+ /** Default font-size inlined on every matching block. */
46
+ defaultFontSize: string;
47
+ }
48
+
36
49
  declare type BlurCallback = () => void;
37
50
 
38
51
  declare type ChangeCallback = (content: string) => void;
@@ -172,6 +185,11 @@ export declare interface EditorConfig {
172
185
  * 'p' (default) emits <p>; 'div' emits <div> (CKEditor ENTER_DIV parity).
173
186
  */
174
187
  forced_root_block?: 'p' | 'div';
188
+ /**
189
+ * Append an empty trailing paragraph when the document ends in a block node
190
+ * (table, image, code block, etc.) so the cursor can be placed after it.
191
+ * Disabled by default.
192
+ */
175
193
  trailingNode?: boolean;
176
194
  includeTemplates?: boolean;
177
195
  templates?: Template[];
package/dist/index.js CHANGED
@@ -47404,6 +47404,59 @@ const FontSize = Extension.create({
47404
47404
  };
47405
47405
  }
47406
47406
  });
47407
+ const BlockFontStyle = Extension.create({
47408
+ name: "blockFontStyle",
47409
+ addOptions() {
47410
+ return {
47411
+ fontFamilyTypes: ["paragraph", "heading"],
47412
+ fontSizeTypes: ["paragraph"],
47413
+ defaultFontFamily: "arial, helvetica, sans-serif",
47414
+ defaultFontSize: "12pt"
47415
+ };
47416
+ },
47417
+ addGlobalAttributes() {
47418
+ return [
47419
+ {
47420
+ types: this.options.fontFamilyTypes,
47421
+ attributes: {
47422
+ // Named blockFontFamily to avoid colliding with the inline
47423
+ // FontFamily mark's `fontFamily` attribute on textStyle.
47424
+ blockFontFamily: {
47425
+ default: this.options.defaultFontFamily,
47426
+ parseHTML: (element) => element.style.fontFamily?.replace(/['"]+/g, "") || this.options.defaultFontFamily,
47427
+ renderHTML: (attributes) => {
47428
+ if (!attributes.blockFontFamily) {
47429
+ return {};
47430
+ }
47431
+ return {
47432
+ style: `font-family: ${attributes.blockFontFamily}`
47433
+ };
47434
+ }
47435
+ }
47436
+ }
47437
+ },
47438
+ {
47439
+ types: this.options.fontSizeTypes,
47440
+ attributes: {
47441
+ // Named blockFontSize to avoid colliding with the inline FontSize
47442
+ // mark's `fontSize` attribute on textStyle.
47443
+ blockFontSize: {
47444
+ default: this.options.defaultFontSize,
47445
+ parseHTML: (element) => element.style.fontSize?.replace(/['"]+/g, "") || this.options.defaultFontSize,
47446
+ renderHTML: (attributes) => {
47447
+ if (!attributes.blockFontSize) {
47448
+ return {};
47449
+ }
47450
+ return {
47451
+ style: `font-size: ${attributes.blockFontSize}`
47452
+ };
47453
+ }
47454
+ }
47455
+ }
47456
+ }
47457
+ ];
47458
+ }
47459
+ });
47407
47460
  const LineHeight = Extension.create({
47408
47461
  name: "lineHeight",
47409
47462
  addOptions() {
@@ -51631,6 +51684,8 @@ const fontNames = "Andale Mono=andale mono,times; Arial=arial,helvetica,sans-ser
51631
51684
  const FULL_TOOLBAR = "bold italic underline strikethrough subscript superscript | blocks styles | bullist numlist outdent indent blockquote | fontfamily fontsize | lineheight alignleft aligncenter alignright alignjustify | forecolor backcolor | removeformat copy cut paste | undo redo | image table charmap emoticons hr | fullscreen preview | code link unlink anchor codesample | ltr rtl | searchreplace";
51632
51685
  const BASIC_TOOLBAR = "bold italic underline strikethrough subscript superscript | bullist numlist outdent indent | fontfamily fontsize blockquote | lineheight alignleft aligncenter alignright alignjustify | forecolor backcolor | removeformat copy cut paste | undo redo | charmap emoticons | link unlink | ltr rtl | searchreplace";
51633
51686
  const DEFAULT_FONT_SIZES = "8pt 9pt 10pt 12pt 14pt 18pt 24pt 36pt";
51687
+ const DEFAULT_FONT_FAMILY = "arial, helvetica, sans-serif";
51688
+ const DEFAULT_FONT_SIZE = "12pt";
51634
51689
  let editorIdCounter = 0;
51635
51690
  let globalTranslate = (key) => key;
51636
51691
  let globalTranslateCustomized = false;
@@ -51921,8 +51976,19 @@ class HTMLEditor {
51921
51976
  Underline,
51922
51977
  TextStyle,
51923
51978
  InlineStyle,
51979
+ // Inline (mark-based) font styling for per-selection changes: produces
51980
+ // <span style="font-family|font-size:…"> so a single paragraph can mix
51981
+ // fonts/sizes.
51924
51982
  FontFamily,
51925
51983
  FontSize,
51984
+ // Block-level default font: inlines font-family on <p>/<div>/<hN> and
51985
+ // font-size on <p>/<div>, from the configured fontName/fontSize, so
51986
+ // exported content carries the base font on the block itself. Inline
51987
+ // spans above still override it for the text they wrap.
51988
+ BlockFontStyle.configure({
51989
+ defaultFontFamily: this.config.fontName ?? DEFAULT_FONT_FAMILY,
51990
+ defaultFontSize: this.config.fontSize ?? DEFAULT_FONT_SIZE
51991
+ }),
51926
51992
  LineHeight,
51927
51993
  Color,
51928
51994
  Highlight.configure({
@@ -52212,6 +52278,7 @@ class HTMLEditor {
52212
52278
  }
52213
52279
  exports.Anchor = Anchor;
52214
52280
  exports.AnchorDialog = AnchorDialog;
52281
+ exports.BlockFontStyle = BlockFontStyle;
52215
52282
  exports.CHAR_MAP = CHAR_MAP;
52216
52283
  exports.CONFAB_ICONS = CONFAB_ICONS;
52217
52284
  exports.CharacterMap = CharacterMap;
package/dist/index.mjs CHANGED
@@ -47402,6 +47402,59 @@ const FontSize = Extension.create({
47402
47402
  };
47403
47403
  }
47404
47404
  });
47405
+ const BlockFontStyle = Extension.create({
47406
+ name: "blockFontStyle",
47407
+ addOptions() {
47408
+ return {
47409
+ fontFamilyTypes: ["paragraph", "heading"],
47410
+ fontSizeTypes: ["paragraph"],
47411
+ defaultFontFamily: "arial, helvetica, sans-serif",
47412
+ defaultFontSize: "12pt"
47413
+ };
47414
+ },
47415
+ addGlobalAttributes() {
47416
+ return [
47417
+ {
47418
+ types: this.options.fontFamilyTypes,
47419
+ attributes: {
47420
+ // Named blockFontFamily to avoid colliding with the inline
47421
+ // FontFamily mark's `fontFamily` attribute on textStyle.
47422
+ blockFontFamily: {
47423
+ default: this.options.defaultFontFamily,
47424
+ parseHTML: (element) => element.style.fontFamily?.replace(/['"]+/g, "") || this.options.defaultFontFamily,
47425
+ renderHTML: (attributes) => {
47426
+ if (!attributes.blockFontFamily) {
47427
+ return {};
47428
+ }
47429
+ return {
47430
+ style: `font-family: ${attributes.blockFontFamily}`
47431
+ };
47432
+ }
47433
+ }
47434
+ }
47435
+ },
47436
+ {
47437
+ types: this.options.fontSizeTypes,
47438
+ attributes: {
47439
+ // Named blockFontSize to avoid colliding with the inline FontSize
47440
+ // mark's `fontSize` attribute on textStyle.
47441
+ blockFontSize: {
47442
+ default: this.options.defaultFontSize,
47443
+ parseHTML: (element) => element.style.fontSize?.replace(/['"]+/g, "") || this.options.defaultFontSize,
47444
+ renderHTML: (attributes) => {
47445
+ if (!attributes.blockFontSize) {
47446
+ return {};
47447
+ }
47448
+ return {
47449
+ style: `font-size: ${attributes.blockFontSize}`
47450
+ };
47451
+ }
47452
+ }
47453
+ }
47454
+ }
47455
+ ];
47456
+ }
47457
+ });
47405
47458
  const LineHeight = Extension.create({
47406
47459
  name: "lineHeight",
47407
47460
  addOptions() {
@@ -51629,6 +51682,8 @@ const fontNames = "Andale Mono=andale mono,times; Arial=arial,helvetica,sans-ser
51629
51682
  const FULL_TOOLBAR = "bold italic underline strikethrough subscript superscript | blocks styles | bullist numlist outdent indent blockquote | fontfamily fontsize | lineheight alignleft aligncenter alignright alignjustify | forecolor backcolor | removeformat copy cut paste | undo redo | image table charmap emoticons hr | fullscreen preview | code link unlink anchor codesample | ltr rtl | searchreplace";
51630
51683
  const BASIC_TOOLBAR = "bold italic underline strikethrough subscript superscript | bullist numlist outdent indent | fontfamily fontsize blockquote | lineheight alignleft aligncenter alignright alignjustify | forecolor backcolor | removeformat copy cut paste | undo redo | charmap emoticons | link unlink | ltr rtl | searchreplace";
51631
51684
  const DEFAULT_FONT_SIZES = "8pt 9pt 10pt 12pt 14pt 18pt 24pt 36pt";
51685
+ const DEFAULT_FONT_FAMILY = "arial, helvetica, sans-serif";
51686
+ const DEFAULT_FONT_SIZE = "12pt";
51632
51687
  let editorIdCounter = 0;
51633
51688
  let globalTranslate = (key) => key;
51634
51689
  let globalTranslateCustomized = false;
@@ -51919,8 +51974,19 @@ class HTMLEditor {
51919
51974
  Underline,
51920
51975
  TextStyle,
51921
51976
  InlineStyle,
51977
+ // Inline (mark-based) font styling for per-selection changes: produces
51978
+ // <span style="font-family|font-size:…"> so a single paragraph can mix
51979
+ // fonts/sizes.
51922
51980
  FontFamily,
51923
51981
  FontSize,
51982
+ // Block-level default font: inlines font-family on <p>/<div>/<hN> and
51983
+ // font-size on <p>/<div>, from the configured fontName/fontSize, so
51984
+ // exported content carries the base font on the block itself. Inline
51985
+ // spans above still override it for the text they wrap.
51986
+ BlockFontStyle.configure({
51987
+ defaultFontFamily: this.config.fontName ?? DEFAULT_FONT_FAMILY,
51988
+ defaultFontSize: this.config.fontSize ?? DEFAULT_FONT_SIZE
51989
+ }),
51924
51990
  LineHeight,
51925
51991
  Color,
51926
51992
  Highlight.configure({
@@ -52211,6 +52277,7 @@ class HTMLEditor {
52211
52277
  export {
52212
52278
  Anchor,
52213
52279
  AnchorDialog,
52280
+ BlockFontStyle,
52214
52281
  CHAR_MAP,
52215
52282
  CONFAB_ICONS,
52216
52283
  CharacterMap,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mdaemon/html-editor",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "A TinyMCE-compatible HTML editor built on TipTap",
5
5
  "homepage": "https://github.com/mdaemon-technologies/MDHTMLEditor",
6
6
  "repository": {