@h-k-dev/angular-email-editor 0.0.2 → 0.0.4

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.
@@ -0,0 +1,144 @@
1
+ /**
2
+ * The fonts an email is written in — Gmail's set, in Gmail's order — as
3
+ * plain data: no Angular, no ProseMirror. The editor's `textStyle` mark
4
+ * stores and emits only these stacks, the toolbar offers them, and an
5
+ * editor of another kind (summernote's `fontNames`) can offer the same set
6
+ * from the same constant, so a message reads the same font whichever
7
+ * composer wrote it.
8
+ */
9
+ /** The clients, in the order a picker shows them (G, A, O), with the letter
10
+ and name it shows them by. */
11
+ const fontClients = [
12
+ { id: 'gmail', letter: 'G', name: 'Gmail' },
13
+ { id: 'apple-mail', letter: 'A', name: 'Apple Mail' },
14
+ { id: 'outlook-desktop', letter: 'O', name: 'Outlook' },
15
+ ];
16
+ /** The family names of a `font-family` value, unquoted, in order. */
17
+ function familiesOf(stack) {
18
+ return stack
19
+ .split(',')
20
+ .map((family) => family.replace(/["']/g, '').trim())
21
+ .filter(Boolean);
22
+ }
23
+ const G = 'gmail';
24
+ const A = 'apple-mail';
25
+ const O = 'outlook-desktop';
26
+ function font(id, name, stack, clients) {
27
+ return { id, name, stack, face: familiesOf(stack)[0], clients };
28
+ }
29
+ /**
30
+ * Gmail's fonts, in its menu's order. A stack is the face, then what a
31
+ * client without it should draw instead, then the generic. Each face leads
32
+ * only its own stack, so a single family read back from another editor
33
+ * (`font-family: 'Arial Black'`) finds its font exactly.
34
+ *
35
+ * The first stack naming a family claims it (see {@link matchEmailFont}):
36
+ * `helvetica` and `sans-serif` read as Sans Serif, `times` and `serif` as
37
+ * Serif, `courier` and `monospace` as Fixed width.
38
+ */
39
+ const emailFontFamilies = [
40
+ font('sans-serif', 'Sans Serif', 'Arial, Helvetica, sans-serif', [G, A, O]),
41
+ font('serif', 'Serif', '"Times New Roman", Times, serif', [G, A, O]),
42
+ font('fixed-width', 'Fixed width', '"Courier New", Courier, monospace', [G, A, O]),
43
+ // Not on iOS.
44
+ font('wide', 'Wide', '"Arial Black", sans-serif', [G, O]),
45
+ // Office's, not Windows' own — nor on iOS.
46
+ font('narrow', 'Narrow', '"Arial Narrow", sans-serif', [O]),
47
+ // Not on iOS.
48
+ font('comic-sans-ms', 'Comic Sans MS', '"Comic Sans MS", sans-serif', [G, O]),
49
+ // Office's only: neither macOS, iOS nor Windows itself has it.
50
+ font('garamond', 'Garamond', 'Garamond, "Times New Roman", serif', [O]),
51
+ font('georgia', 'Georgia', 'Georgia, serif', [G, A, O]),
52
+ // Not on iOS.
53
+ font('tahoma', 'Tahoma', 'Tahoma, sans-serif', [G, O]),
54
+ font('trebuchet-ms', 'Trebuchet MS', '"Trebuchet MS", sans-serif', [G, A, O]),
55
+ font('verdana', 'Verdana', 'Verdana, sans-serif', [G, A, O]),
56
+ ];
57
+ /**
58
+ * The font a message is written in until the writer picks another — Gmail's
59
+ * Sans Serif, Arial. Nothing is emitted for it: unstyled text is drawn in
60
+ * the client's own default, as Gmail's is. An editor shows it as its
61
+ * surface font, so what is written looks as it will in Gmail; summernote
62
+ * takes its face (`fontName: emailDefaultFont.face`).
63
+ */
64
+ const emailDefaultFont = emailFontFamilies[0];
65
+ /**
66
+ * The faces of {@link emailFontFamilies}, in order — the set for an editor
67
+ * that offers single families. For summernote, both lists: `fontNamesIgnoreCheck`
68
+ * keeps a face this machine lacks (Garamond, Arial Narrow) in the menu.
69
+ *
70
+ * ```ts
71
+ * $('#editor').summernote({ fontNames: emailFontFaces, fontNamesIgnoreCheck: emailFontFaces });
72
+ * ```
73
+ */
74
+ const emailFontFaces = emailFontFamilies.map((f) => f.face);
75
+ /** Every size the editor stores, in px. */
76
+ const allowedFontSizes = [10, 12, 14, 16, 18, 24, 32];
77
+ /**
78
+ * The sizes a picker offers: the phone-safe subset (≥14px). Below ~13px iOS
79
+ * auto-inflates text and reflows the layout, so they are not *offered* —
80
+ * but every {@link allowedFontSizes} size is still read and kept, because a
81
+ * hand-typed size in the HTML source is the author's own responsibility.
82
+ */
83
+ const emailFontSizes = [14, 16, 18, 24, 32];
84
+ /** A `font-family` value as a comparison key: lower-cased, quotes dropped,
85
+ whitespace around commas collapsed — so a hand-typed or CSSOM-reserialized
86
+ stack matches a curated one regardless of cosmetic differences. */
87
+ function fontFamilyKey(raw) {
88
+ return raw
89
+ .toLowerCase()
90
+ .replace(/["']/g, '')
91
+ .replace(/\s*,\s*/g, ',')
92
+ .trim();
93
+ }
94
+ const FONT_BY_KEY = new Map(emailFontFamilies.map((f) => [fontFamilyKey(f.stack), f]));
95
+ /** Each family a stack names to the first stack naming it. */
96
+ const FONT_BY_FAMILY = new Map();
97
+ for (const f of emailFontFamilies) {
98
+ for (const family of fontFamilyKey(f.stack).split(',')) {
99
+ if (!FONT_BY_FAMILY.has(family))
100
+ FONT_BY_FAMILY.set(family, f);
101
+ }
102
+ }
103
+ /** Whether `value` is exactly one of the stacks, give or take quotes, case
104
+ and spacing. */
105
+ function isEmailFontStack(value) {
106
+ return typeof value === 'string' && FONT_BY_KEY.has(fontFamilyKey(value));
107
+ }
108
+ /**
109
+ * The font a `font-family` value is. One of the stacks is itself; a stack of
110
+ * someone else's is the font it falls back to — the first of its families a
111
+ * stack names, its generic last: a builder's web font (`Ubuntu, Helvetica,
112
+ * Arial, sans-serif`) is Sans Serif, the face a client without that font
113
+ * draws anyway, and summernote's `'Comic Sans MS'` is Comic Sans MS.
114
+ * Nothing to fall back to, no font.
115
+ */
116
+ function matchEmailFont(raw) {
117
+ if (!raw)
118
+ return null;
119
+ const key = fontFamilyKey(raw);
120
+ const exact = FONT_BY_KEY.get(key);
121
+ if (exact)
122
+ return exact;
123
+ for (const family of key.split(',')) {
124
+ const found = FONT_BY_FAMILY.get(family.trim());
125
+ if (found)
126
+ return found;
127
+ }
128
+ return null;
129
+ }
130
+
131
+ /*
132
+ * Public API Surface of @h-k-dev/angular-email-editor/fonts
133
+ *
134
+ * Its own entry because it is plain data: a host whose other composer is
135
+ * not this editor (summernote) shares the font set without pulling in
136
+ * ProseMirror or Angular.
137
+ */
138
+
139
+ /**
140
+ * Generated bundle index. Do not edit.
141
+ */
142
+
143
+ export { allowedFontSizes, emailDefaultFont, emailFontFaces, emailFontFamilies, emailFontSizes, fontClients, fontFamilyKey, isEmailFontStack, matchEmailFont };
144
+ //# sourceMappingURL=h-k-dev-angular-email-editor-fonts.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"h-k-dev-angular-email-editor-fonts.mjs","sources":["../../../projects/angular-email-editor/fonts/fonts.ts","../../../projects/angular-email-editor/fonts/public-api.ts","../../../projects/angular-email-editor/fonts/h-k-dev-angular-email-editor-fonts.ts"],"sourcesContent":["/**\n * The fonts an email is written in — Gmail's set, in Gmail's order — as\n * plain data: no Angular, no ProseMirror. The editor's `textStyle` mark\n * stores and emits only these stacks, the toolbar offers them, and an\n * editor of another kind (summernote's `fontNames`) can offer the same set\n * from the same constant, so a message reads the same font whichever\n * composer wrote it.\n */\n\n/**\n * A client a font is checked against — the three a writer's recipients\n * mostly read in, the same ids as the library's `RenderingClient`.\n */\nexport type FontClient = 'gmail' | 'apple-mail' | 'outlook-desktop';\n\n/** The clients, in the order a picker shows them (G, A, O), with the letter\n and name it shows them by. */\nexport const fontClients: readonly { id: FontClient; letter: string; name: string }[] = [\n { id: 'gmail', letter: 'G', name: 'Gmail' },\n { id: 'apple-mail', letter: 'A', name: 'Apple Mail' },\n { id: 'outlook-desktop', letter: 'O', name: 'Outlook' },\n];\n\n/** A font the editor offers: one of {@link emailFontFamilies}. */\nexport interface EmailFont {\n /** Stable, for a host's translation key: `sans-serif`, `fixed-width`, … */\n readonly id: string;\n /** The label, in English — Gmail's words. */\n readonly name: string;\n /**\n * The exact `font-family` value emitted — the canonical stored form. A\n * family name of more than one word is double-quoted: the CSSOM (Chrome's\n * and jsdom's alike) quotes it on reserialization, so the stored bytes are\n * already what comes back and a round trip is stable.\n */\n readonly stack: string;\n /** The face the stack is for — its first family, unquoted: what an editor\n that sets a single family (summernote) offers for it. */\n readonly face: string;\n /**\n * The clients that draw the face itself rather than its fallback — the\n * face is on the machine the client runs on:\n *\n * - `gmail`: Gmail on the web, read on Windows or macOS (it draws with\n * the reader's own fonts; one of them lacking the face is a no).\n * - `apple-mail`: Apple Mail on macOS *and* iOS — a phone lacks Arial\n * Black, Comic Sans, Tahoma.\n * - `outlook-desktop`: Outlook on Windows, which brings Office's fonts\n * (Arial Narrow, Garamond).\n *\n * Elsewhere the stack's fallback draws: the email still reads, in a near\n * face. Curated, conservative — a face only some readers have is a no.\n */\n readonly clients: readonly FontClient[];\n}\n\n/** The family names of a `font-family` value, unquoted, in order. */\nfunction familiesOf(stack: string): string[] {\n return stack\n .split(',')\n .map((family) => family.replace(/[\"']/g, '').trim())\n .filter(Boolean);\n}\n\nconst G: FontClient = 'gmail';\nconst A: FontClient = 'apple-mail';\nconst O: FontClient = 'outlook-desktop';\n\nfunction font(id: string, name: string, stack: string, clients: FontClient[]): EmailFont {\n return { id, name, stack, face: familiesOf(stack)[0], clients };\n}\n\n/**\n * Gmail's fonts, in its menu's order. A stack is the face, then what a\n * client without it should draw instead, then the generic. Each face leads\n * only its own stack, so a single family read back from another editor\n * (`font-family: 'Arial Black'`) finds its font exactly.\n *\n * The first stack naming a family claims it (see {@link matchEmailFont}):\n * `helvetica` and `sans-serif` read as Sans Serif, `times` and `serif` as\n * Serif, `courier` and `monospace` as Fixed width.\n */\nexport const emailFontFamilies: readonly EmailFont[] = [\n font('sans-serif', 'Sans Serif', 'Arial, Helvetica, sans-serif', [G, A, O]),\n font('serif', 'Serif', '\"Times New Roman\", Times, serif', [G, A, O]),\n font('fixed-width', 'Fixed width', '\"Courier New\", Courier, monospace', [G, A, O]),\n // Not on iOS.\n font('wide', 'Wide', '\"Arial Black\", sans-serif', [G, O]),\n // Office's, not Windows' own — nor on iOS.\n font('narrow', 'Narrow', '\"Arial Narrow\", sans-serif', [O]),\n // Not on iOS.\n font('comic-sans-ms', 'Comic Sans MS', '\"Comic Sans MS\", sans-serif', [G, O]),\n // Office's only: neither macOS, iOS nor Windows itself has it.\n font('garamond', 'Garamond', 'Garamond, \"Times New Roman\", serif', [O]),\n font('georgia', 'Georgia', 'Georgia, serif', [G, A, O]),\n // Not on iOS.\n font('tahoma', 'Tahoma', 'Tahoma, sans-serif', [G, O]),\n font('trebuchet-ms', 'Trebuchet MS', '\"Trebuchet MS\", sans-serif', [G, A, O]),\n font('verdana', 'Verdana', 'Verdana, sans-serif', [G, A, O]),\n];\n\n/**\n * The font a message is written in until the writer picks another — Gmail's\n * Sans Serif, Arial. Nothing is emitted for it: unstyled text is drawn in\n * the client's own default, as Gmail's is. An editor shows it as its\n * surface font, so what is written looks as it will in Gmail; summernote\n * takes its face (`fontName: emailDefaultFont.face`).\n */\nexport const emailDefaultFont: EmailFont = emailFontFamilies[0];\n\n/**\n * The faces of {@link emailFontFamilies}, in order — the set for an editor\n * that offers single families. For summernote, both lists: `fontNamesIgnoreCheck`\n * keeps a face this machine lacks (Garamond, Arial Narrow) in the menu.\n *\n * ```ts\n * $('#editor').summernote({ fontNames: emailFontFaces, fontNamesIgnoreCheck: emailFontFaces });\n * ```\n */\nexport const emailFontFaces: readonly string[] = emailFontFamilies.map((f) => f.face);\n\n/** Every size the editor stores, in px. */\nexport const allowedFontSizes = [10, 12, 14, 16, 18, 24, 32] as const;\nexport type FontSize = (typeof allowedFontSizes)[number];\n\n/**\n * The sizes a picker offers: the phone-safe subset (≥14px). Below ~13px iOS\n * auto-inflates text and reflows the layout, so they are not *offered* —\n * but every {@link allowedFontSizes} size is still read and kept, because a\n * hand-typed size in the HTML source is the author's own responsibility.\n */\nexport const emailFontSizes: readonly FontSize[] = [14, 16, 18, 24, 32];\n\n/** A `font-family` value as a comparison key: lower-cased, quotes dropped,\n whitespace around commas collapsed — so a hand-typed or CSSOM-reserialized\n stack matches a curated one regardless of cosmetic differences. */\nexport function fontFamilyKey(raw: string): string {\n return raw\n .toLowerCase()\n .replace(/[\"']/g, '')\n .replace(/\\s*,\\s*/g, ',')\n .trim();\n}\n\nconst FONT_BY_KEY = new Map(emailFontFamilies.map((f) => [fontFamilyKey(f.stack), f]));\n\n/** Each family a stack names to the first stack naming it. */\nconst FONT_BY_FAMILY = new Map<string, EmailFont>();\nfor (const f of emailFontFamilies) {\n for (const family of fontFamilyKey(f.stack).split(',')) {\n if (!FONT_BY_FAMILY.has(family)) FONT_BY_FAMILY.set(family, f);\n }\n}\n\n/** Whether `value` is exactly one of the stacks, give or take quotes, case\n and spacing. */\nexport function isEmailFontStack(value: unknown): value is string {\n return typeof value === 'string' && FONT_BY_KEY.has(fontFamilyKey(value));\n}\n\n/**\n * The font a `font-family` value is. One of the stacks is itself; a stack of\n * someone else's is the font it falls back to — the first of its families a\n * stack names, its generic last: a builder's web font (`Ubuntu, Helvetica,\n * Arial, sans-serif`) is Sans Serif, the face a client without that font\n * draws anyway, and summernote's `'Comic Sans MS'` is Comic Sans MS.\n * Nothing to fall back to, no font.\n */\nexport function matchEmailFont(raw: string | null | undefined): EmailFont | null {\n if (!raw) return null;\n const key = fontFamilyKey(raw);\n const exact = FONT_BY_KEY.get(key);\n if (exact) return exact;\n for (const family of key.split(',')) {\n const found = FONT_BY_FAMILY.get(family.trim());\n if (found) return found;\n }\n return null;\n}\n","/*\n * Public API Surface of @h-k-dev/angular-email-editor/fonts\n *\n * Its own entry because it is plain data: a host whose other composer is\n * not this editor (summernote) shares the font set without pulling in\n * ProseMirror or Angular.\n */\n\nexport * from './fonts';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -3,6 +3,8 @@ import { NodeSelection, TextSelection, Plugin, PluginKey, EditorState, Selection
3
3
  import { keymap } from 'prosemirror-keymap';
4
4
  import { splitBlockAs, chainCommands, newlineInCode, createParagraphNear, liftEmptyBlock, setBlockType, exitCode, lift, wrapIn, toggleMark as toggleMark$1, baseKeymap } from 'prosemirror-commands';
5
5
  import { tableEditing, fixTables, splitCell, mergeCells, deleteTable, deleteColumn, deleteRow, addRowAfter, addRowBefore, setCellAttr, removeColumn as removeColumn$1, removeRow, addColumn as addColumn$1, addRow, addColumnAfter, addColumnBefore, TableMap, isInTable, selectedRect, CellSelection, nextCell, goToNextCell } from 'prosemirror-tables';
6
+ import { allowedFontSizes, isEmailFontStack, matchEmailFont } from '@h-k-dev/angular-email-editor/fonts';
7
+ export * from '@h-k-dev/angular-email-editor/fonts';
6
8
  import { AddMarkStep, RemoveMarkStep, Transform } from 'prosemirror-transform';
7
9
  import { closeHistory, redo, undo, history } from 'prosemirror-history';
8
10
  import { InputRule, inputRules, wrappingInputRule, textblockTypeInputRule } from 'prosemirror-inputrules';
@@ -1686,9 +1688,8 @@ function isUppercase(state, schema) {
1686
1688
  });
1687
1689
  return found;
1688
1690
  }
1689
- const ALLOWED_SIZES = [10, 12, 14, 16, 18, 24, 32];
1690
1691
  function isSafeFontSize(value) {
1691
- return ALLOWED_SIZES.includes(value);
1692
+ return allowedFontSizes.includes(value);
1692
1693
  }
1693
1694
  /**
1694
1695
  * Parse a font-size value from the DOM into one of our allowed sizes.
@@ -1705,8 +1706,8 @@ function parseFontSize(raw) {
1705
1706
  // A size off the ladder — a builder's 11px, 13px, 15px — snaps to the
1706
1707
  // nearest rung, upward on a tie: read as the size it is nearest to, not
1707
1708
  // dropped to the default. (The schema still emits only its own rungs.)
1708
- let nearest = ALLOWED_SIZES[0];
1709
- for (const size of ALLOWED_SIZES) {
1709
+ let nearest = allowedFontSizes[0];
1710
+ for (const size of allowedFontSizes) {
1710
1711
  const better = Math.abs(size - n) < Math.abs(nearest - n) ||
1711
1712
  (Math.abs(size - n) === Math.abs(nearest - n) && size > nearest);
1712
1713
  if (better)
@@ -1714,79 +1715,19 @@ function parseFontSize(raw) {
1714
1715
  }
1715
1716
  return nearest;
1716
1717
  }
1717
- /**
1718
- * The sizes the toolbar picker offers: the phone-safe subset (≥14px). Below
1719
- * ~13px iOS auto-inflates text and reflows the layout (responsiveness ledger,
1720
- * principle 8), so we don't *offer* those — but {@link parseFontSize} still
1721
- * accepts the full {@link ALLOWED_SIZES} range, because a hand-typed size in
1722
- * the HTML source pane is the author's own responsibility, exactly like a
1723
- * hand-typed hex colour.
1724
- */
1725
- const emailFontSizes = [14, 16, 18, 24, 32];
1726
- /**
1727
- * The curated font stacks — the picker offers only these, no free-form fonts
1728
- * (principle 7: if a mainstream client can't render it, we don't emit it).
1729
- *
1730
- * Deliberately built from *single-word* family identifiers plus a generic
1731
- * fallback: a stack like `Courier New` would round-trip through the CSSOM
1732
- * (serialization builds real elements and re-reads them) and come back quoted
1733
- * as `"Courier New"` in Chrome but unquoted in jsdom — a byte-instability that
1734
- * breaks canonical determinism and makes tests disagree with the runtime (the
1735
- * same trap the longhand/`rgb()` rule guards against). Bare identifiers and
1736
- * generic keywords serialize identically everywhere.
1737
- */
1738
- const emailFontFamilies = [
1739
- { name: 'Sans-serif', stack: 'Arial, Helvetica, sans-serif' },
1740
- { name: 'Serif', stack: 'Georgia, Times, serif' },
1741
- { name: 'Monospace', stack: 'Courier, monospace' },
1742
- { name: 'System', stack: 'system-ui, sans-serif' },
1743
- ];
1744
- /** Normalise a `font-family` value to a comparison key: lower-cased, quotes
1745
- dropped, whitespace around commas collapsed. Lets a hand-typed or CSSOM-
1746
- reserialized stack match a curated one regardless of cosmetic differences. */
1747
- function fontFamilyKey(raw) {
1748
- return raw
1749
- .toLowerCase()
1750
- .replace(/["']/g, '')
1751
- .replace(/\s*,\s*/g, ',')
1752
- .trim();
1753
- }
1754
- const FONT_STACK_BY_KEY = new Map(emailFontFamilies.map((f) => [fontFamilyKey(f.stack), f.stack]));
1755
- /** Each family a curated stack names — a face or its generic — to the first
1756
- stack naming it: `helvetica` and `sans-serif` to Sans-serif, `times` and
1757
- `serif` to Serif. */
1758
- const FONT_STACK_BY_FAMILY = new Map();
1759
- for (const { stack } of emailFontFamilies) {
1760
- for (const family of fontFamilyKey(stack).split(',')) {
1761
- if (!FONT_STACK_BY_FAMILY.has(family))
1762
- FONT_STACK_BY_FAMILY.set(family, stack);
1763
- }
1764
- }
1718
+ /** Whether `value` is one of the curated stacks (`@h-k-dev/angular-email-editor/fonts`). */
1765
1719
  function isSafeFontFamily(value) {
1766
- return typeof value === 'string' && FONT_STACK_BY_KEY.has(fontFamilyKey(value));
1720
+ return isEmailFontStack(value);
1767
1721
  }
1768
1722
  /**
1769
- * Parse a font-family value from the DOM into one of our curated stacks,
1723
+ * Parse a font-family value from the DOM into one of the curated stacks,
1770
1724
  * returning the *canonical* stack string (so a cosmetically different but
1771
1725
  * equivalent input normalises to the exact bytes we emit). A stack of
1772
- * someone else's reads as the curated one it falls back to — the first of
1773
- * its families a curated stack names, its generic last: a builder's web
1774
- * font (`Ubuntu, Helvetica, Arial, sans-serif`) is Sans-serif, the face a
1775
- * client without that font draws anyway. Nothing to fall back to, no font.
1726
+ * someone else's reads as the curated one it falls back to
1727
+ * ({@link matchEmailFont}). Nothing to fall back to, no font.
1776
1728
  */
1777
1729
  function parseFontFamily(raw) {
1778
- if (!raw)
1779
- return null;
1780
- const key = fontFamilyKey(raw);
1781
- const exact = FONT_STACK_BY_KEY.get(key);
1782
- if (exact)
1783
- return exact;
1784
- for (const family of key.split(',')) {
1785
- const stack = FONT_STACK_BY_FAMILY.get(family.trim());
1786
- if (stack)
1787
- return stack;
1788
- }
1789
- return null;
1730
+ return matchEmailFont(raw)?.stack ?? null;
1790
1731
  }
1791
1732
  /**
1792
1733
  * TipTap-style `textStyle` mark: a `<span style="…">` container holding inline
@@ -15626,12 +15567,16 @@ const createBubbleMenu = (options) => defineExtension({
15626
15567
  let mouseSelecting = false;
15627
15568
  let destroyed = false;
15628
15569
  let open = false;
15570
+ // Where the open menu stands (`anchor: 'first'`): the range or the
15571
+ // node it opened over, and the box measured there.
15572
+ let pinned = null;
15629
15573
  // Closed is said once: a caret moving through the text, or a press
15630
15574
  // elsewhere on the page, is no news to a host that already knows.
15631
15575
  const close = () => {
15632
15576
  if (!open)
15633
15577
  return;
15634
15578
  open = false;
15579
+ pinned = null;
15635
15580
  options.onStateChange({ isOpen: false, boundingBox: null });
15636
15581
  };
15637
15582
  // Whether the menu may show: not mid-drag, the host's say-so, and
@@ -15641,40 +15586,16 @@ const createBubbleMenu = (options) => defineExtension({
15641
15586
  !mouseSelecting &&
15642
15587
  (options.shouldShow || defaultBubbleShouldShow)(view.state) &&
15643
15588
  view.hasFocus();
15644
- // Reports the menu open over the current selection.
15645
- const show = () => {
15646
- // Asked again once the delay is over: in between, the host may
15647
- // have opened something of its own there (a click on a button
15648
- // opens its link editor) that its `shouldShow` now says no to.
15649
- if (!canShow())
15650
- return close();
15651
- // An image alone, or a button: the menu stands over the node
15652
- // itself.
15653
- const image = selectedImage(view.state);
15654
- const button = image ? null : selectedButton(view.state);
15655
- const node = image ?? button;
15656
- const dom = node && view.nodeDOM(node.pos);
15657
- if (dom && typeof dom.getBoundingClientRect === 'function') {
15658
- open = true;
15659
- options.onStateChange({
15660
- isOpen: true,
15661
- boundingBox: dom.getBoundingClientRect(),
15662
- kind: image ? 'image' : 'button',
15663
- });
15664
- return;
15665
- }
15666
- const { from, to } = view.state.selection;
15667
- // Get coordinates of the selection boundaries
15589
+ // The box of a range: from its start to its end, over every line it
15590
+ // takes — the virtual DOMRect the host's overlay anchors to.
15591
+ const rangeBox = (from, to) => {
15668
15592
  const start = view.coordsAtPos(from);
15669
15593
  const end = view.coordsAtPos(to, -1);
15670
- // Construct a virtual DOMRect representing the text selection.
15671
- // Angular CDK uses this to anchor the overlay!
15672
15594
  const top = Math.min(start.top, end.top);
15673
15595
  const bottom = Math.max(start.bottom, end.bottom);
15674
15596
  const left = Math.min(start.left, end.left);
15675
15597
  const right = Math.max(start.right, end.right);
15676
- // Construct a mathematically perfect virtual DOMRect
15677
- const boundingBox = {
15598
+ return {
15678
15599
  top,
15679
15600
  bottom,
15680
15601
  left,
@@ -15685,8 +15606,51 @@ const createBubbleMenu = (options) => defineExtension({
15685
15606
  y: top,
15686
15607
  toJSON: () => '',
15687
15608
  };
15609
+ };
15610
+ // The box of a node: its own element's, while it has one.
15611
+ const nodeBox = (pos) => {
15612
+ const dom = view.nodeDOM(pos);
15613
+ return dom && typeof dom.getBoundingClientRect === 'function'
15614
+ ? dom.getBoundingClientRect()
15615
+ : null;
15616
+ };
15617
+ // Reports the menu open over the current selection — standing
15618
+ // where it opened (`anchor: 'first'`), or over the selection of
15619
+ // the moment. `remeasure`: the pinned place has moved on screen
15620
+ // (a scroll), so its box is measured again.
15621
+ const show = (remeasure = false) => {
15622
+ // Asked again once the delay is over: in between, the host may
15623
+ // have opened something of its own there (a click on a button
15624
+ // opens its link editor) that its `shouldShow` now says no to.
15625
+ if (!canShow())
15626
+ return close();
15627
+ // An image alone, or a button: the menu is for the node, and
15628
+ // stands over the node itself — while it has an element to
15629
+ // stand over; text otherwise.
15630
+ const image = selectedImage(view.state);
15631
+ const button = image ? null : selectedButton(view.state);
15632
+ const node = image ?? button;
15633
+ const box = node ? nodeBox(node.pos) : null;
15634
+ const kind = box ? (image ? 'image' : 'button') : 'text';
15635
+ if (pinned && (options.anchor ?? 'first') === 'first') {
15636
+ if (remeasure) {
15637
+ // The same place, where it now is — clamped, in case the
15638
+ // document shrank under it since.
15639
+ const size = view.state.doc.content.size;
15640
+ const from = Math.min(pinned.from, size);
15641
+ pinned.box =
15642
+ (pinned.node ? nodeBox(from) : rangeBox(from, Math.min(pinned.to, size))) ??
15643
+ pinned.box;
15644
+ }
15645
+ options.onStateChange({ isOpen: true, boundingBox: pinned.box, kind });
15646
+ return;
15647
+ }
15648
+ const { from, to } = view.state.selection;
15649
+ pinned = box
15650
+ ? { from: node.pos, to: node.pos, node: true, box }
15651
+ : { from, to, node: false, box: rangeBox(from, to) };
15688
15652
  open = true;
15689
- options.onStateChange({ isOpen: true, boundingBox, kind: 'text' });
15653
+ options.onStateChange({ isOpen: true, boundingBox: pinned.box, kind });
15690
15654
  };
15691
15655
  const refresh = () => {
15692
15656
  if (destroyed)
@@ -15696,16 +15660,17 @@ const createBubbleMenu = (options) => defineExtension({
15696
15660
  close();
15697
15661
  return;
15698
15662
  }
15699
- // Open already: the menu follows the selection *now* — its kind
15700
- // and its box change in the same transaction the selection did,
15701
- // so what a host renders from the state and what it reads live
15702
- // from the editor (an image's alt, an action's enabled) never
15703
- // disagree. Delayed, the image's menu stood over a text range
15704
- // for the delay, showing the alt of an image no longer selected
15705
- // alone — empty — and its image tools disabled, before the
15706
- // text's menu replaced it. The delay is for *opening*: a range
15707
- // passing through, a drag's intermediate selections, never pop
15708
- // a menu of their own.
15663
+ // Open already: the menu answers the selection *now* — its kind
15664
+ // (and, following the selection, its box) changes in the same
15665
+ // transaction the selection did, so what a host renders from the
15666
+ // state and what it reads live from the editor (an image's alt,
15667
+ // an action's enabled) never disagree. Delayed, the image's menu
15668
+ // showed the alt of an image no longer selected alone — empty —
15669
+ // and its image tools disabled, for the delay, before the text's
15670
+ // menu replaced it. The delay is for *opening*: a range passing
15671
+ // through, a drag's intermediate selections, never pop a menu of
15672
+ // their own. Pinned (`anchor: 'first'`), the box stays where the
15673
+ // menu opened.
15709
15674
  if (open)
15710
15675
  return show();
15711
15676
  showTimer = setTimeout(show, options.updateDelay ?? 150);
@@ -15742,7 +15707,7 @@ const createBubbleMenu = (options) => defineExtension({
15742
15707
  close,
15743
15708
  refresh: () => {
15744
15709
  if (open)
15745
- show();
15710
+ show(true);
15746
15711
  },
15747
15712
  });
15748
15713
  return {
@@ -18816,5 +18781,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
18816
18781
  * Generated bundle index. Do not edit.
18817
18782
  */
18818
18783
 
18819
- export { AUTHORED_ATTR, AUTHORED_SPEC_KEY, AUTHORED_STYLE_DEFAULTS_KEY, AuthoredEnter, BLOCKQUOTE_STYLE, BLOCK_MENU_FOCUS_KEY, BUTTON_FILL, BUTTON_STYLE, BaseKeymap, Blockquote, Bold, BulletList, Button, CARET_ROOM, CLIENT_LABELS, COMMENT_TAG, CONTENT_ATTRS, CSS_SUPPORT, ClearFormatting, CodeLine, CodeLineIndent, Column, ColumnResize, Columns, ColumnsResize, DOCUMENT_CLASS, DOCUMENT_TAGS, DUAL_BACKGROUND_MIN_RATIO, DUAL_CONTRAST_DARK, DUAL_CONTRAST_LIGHT, DUAL_CONTRAST_MIN_RATIO, Divider, Document$1 as Document, DocumentStyles, EMAIL_ATTRIBUTES, EMAIL_CSS_PROPERTIES, EMAIL_SAFE_STYLE_PROPERTIES, EMAIL_SAFE_TAGS, EMAIL_TAGS, EMAIL_TAG_ATTRIBUTES, EmailParagraph, FILE_CHOOSER_POINTER_WAIT, FILL_TEXT_COLOR, FILL_TEXT_COLOR_LIGHT, FILL_TEXT_COLOR_RGB, FOLD_WIDTH, FORMAT_WIDTH, GMAIL_CLIP_BYTES, GUIDES_ACTIVE_CLASS, GUIDES_PEEK_CLASS, GUIDES_PEEK_DELAY_MS, Gapcursor, HEADING_SIZES, HardBreak, Heading, History, HtmlComment, HtmlCommentInline, HtmlElement, HtmlInline, HtmlLanguage, HtmlRaw, HtmlTextElement, HtmlVoid, HtmlVoidBlock, IMPORT_VIEWPORT_WIDTH, INDENT_MAX, INDENT_STEP, INLINE_TAGS, INLINE_VOID_TAGS, IN_SELECTION_CLASS, Image, InlineAtomSelection, InlineImageStore, InlineImages, Italic, LIST_STYLE, LayoutGuides, Link, ListItem, MAX_COLUMNS, MAX_IMAGE_WIDTH, MAX_MERGE_TAG_LENGTH, MAX_UNBROKEN_RUN, MIN_COLUMN_CAP, MIN_COLUMN_PCT, MIN_FONT_SIZE, MIN_IMAGE_WIDTH, MIN_TABLE_PCT, MJML_WORLDLY_HTML, MergeTag, NoTextDrag, OrderedList, PARSE_SCOPE_KEY, PLACEHOLDER_WIDTH, Paragraph, PasteHygiene, QuotedHistory, REFUSED_TAGS, RENDERING_CLIENTS, SECTION_CONTENT_MAX, SECTION_INSET, SECTION_PADDING, STACK_CLASS, STACK_RULE, Section, SplitKeepingMarks, TABLE_BORDER_COLOR, TABLE_CELL_PADDING, TABLE_SECTION_TAGS, TYPING_REST, Table, TableCell, TableRow, Text, TextStyle, UNSET_BUTTON_HREF, Underline, VOID_TAGS, acceptProposal, addColumn, addColumnAtEnd, addRowAtEnd, analyzeAngularExpression, angularDialect, angularRequiredFields, applyAuthoredAttributes, applyEmailVocabulary, attributeString, authoredAttribute, authoredMarkupOf, authoredViewAttributes, bareButtons, buttonStyle, canonicalHead, canonicalMergeTagInner, canonicalRender, caretCellPos, caretInsideMergeTag, claimedImageFiles, clearCells, clientList, columnCaps, columnWidths, completionContextAt, containerStyle, contrastRatio, correctStoredMistakes, createAngularExpressions, createBlockMenu, createBubbleMenu, createButtonEdit, createContentProposal, createContentStream, createDOMParser, createEditor, createHtmlAutocomplete, createHtmlLanguage, createImageDrag, createInlineImages, createMergeTagResolution, createOffsetMapper, createQuotedHistory, createSchema, createSendIntent, createSourceMarks, createSuggestionMenu, createTableHandles, declarationProperty, declaredBackground, decodeDataUrl, defaultBubbleShouldShow, defineExtension, defineMark, defineNode, deleteColumns, deleteFullySelected, discardProposal, distributePadding, docText, dropDeadOfficeClasses, dropHidden, dropMediaQueries, dropZeroSizedWhitespace, duplicateColumn, duplicateRow, editQuotedHistory, effectiveWidths, emailBackgroundPalette, emailDocument, emailExtensions, emailFontFamilies, emailFontSizes, emailPlainText, emailSizeBudget, emailTextPalette, embedsAsLinks, entitySpans, escapeAttribute$2 as escapeAttribute, escapeText$1 as escapeText, expressionDialect, expressionDialectKey, extensionActions, extensionSuggestions, fillTextColor, filledPlaceholderAttrs, filterEmailStyle, findColumnContext, findColumnsContext, findCssIssues, findListDepth, findSectionContext, findTableContext, fitImageWidth, foldHTML, formatHTML, formatPct, forwardDocument, forwardQuote, hasBlockChildren$1 as hasBlockChildren, hasDocumentEnvelope, headingStyle, holdsBlock, holdsColumn, hrefProblem, htmlSourceExtensions, imageDropTarget, importLoss, importedDocument, inheritTextStyles, inheritedMarkup, inlineBootstrapTableBorders, inlineImageCids, inlineImageRegistry, inlineImagesKey, inlineStyles, insertHTML, insertMergeTag, isActionEnabled, isBlock$1 as isBlock, isBlockLevel, isBlockish, isBooleanAttribute, isEmailAttribute, isEmailCssProperty, isEmailTag, isFillTextColor, isInlineAtom, isMarkActive, isMergeTagExpression, isMergeTagPath, isNodeActive, isPadded, isProposing, isQuotedHistoryFolded, isSafeColor, isSafeFontFamily, isSafeFontSize, isSafeUrl$1 as isSafeUrl, isSectionImageUrl, isStreaming, italicStarInputRegex, italicStarPasteRegex, italicUnderscoreInputRegex, italicUnderscorePasteRegex, keepGmailRules, layoutBlockAt, linkClickPlugin, linkPastePlugin, linkRangeAt, lintHTML, lowerInlinesAroundBlocks, markAttrsOf, markStackingColumns, marksAcrossBreak, materializeComments, measureMenuPlacement, mediaMatches, mergeTagAt, mergeTagExpressions, mergeTagFields, mergeTagRanges, mergeTagResolutionPending, moveColumn, moveRow, normalizeCommentText, normalizeCss, normalizeHref, normalizeMergeTagText, noteOwnWidths, openFileChooser, openTag$1 as openTag, openTags, outlookColumns, paddingOf, parseAngularExpression, parseDocument, parseFontFamily, parseFontSize, parseHTML, parsePadding, parseRules, parseTextTransform, passesDualBackground, passesDualContrast, preserveExtensions, preservedAttributes, promoteInlineImages, promoteMergeTags, proposalRange, proposeContent, quotedHistory, readEnvelope, readImageFile, realizeComments, relativeLuminance, removeColumn, removeQuotedHistory, renderForClient, renderedPath, repairLinkSchemes, repairTables, replaceHTML, replyDocument, replyEnvelope, replyQuote, reviseProposal, rewriteInlineImageSources, richTextExtensions, ruleForScope, ruleScope, sanitizePastedHTML, scanHTML, scanMergeTags, scopeOf$1 as scopeOf, scopedDocumentCss, selectColumn, selectRow, selectedButton, selectedImage, selectedImageAlt, selectedMarkAtom, selectionInsideMergeTag, serializeDocument, serializeToHTML, setCellBackground, setColumnBackground, setColumnBoundary, setColumnsBoundary, setQuotedHistory, setSectionBackground, setSectionImage, setTableBox, setTableWidth, soleInlineAtom, splitDeclarations$2 as splitDeclarations, splitListItemKeepMarks, starInputRegex, starPasteRegex, stopProposal, streamContent, streamedRange, streamingRange, suggestionSectionTitles, tableStyle, textOffsetAt, textRegions, toEmailSafeColor, toInboundMessage, toggleList, trimInlineBoxes, underscoreInputRegex, underscorePasteRegex, unwrapLayoutTables, unwrapOfficeParagraphMarks, verbatimElement, videoPage, watchMenuScroll, withAttribute, withAuthoredMarkup, withQuoted, withQuotedHistory, withStyleDeclaration, withoutAttribute, withoutStyleDeclaration };
18784
+ export { AUTHORED_ATTR, AUTHORED_SPEC_KEY, AUTHORED_STYLE_DEFAULTS_KEY, AuthoredEnter, BLOCKQUOTE_STYLE, BLOCK_MENU_FOCUS_KEY, BUTTON_FILL, BUTTON_STYLE, BaseKeymap, Blockquote, Bold, BulletList, Button, CARET_ROOM, CLIENT_LABELS, COMMENT_TAG, CONTENT_ATTRS, CSS_SUPPORT, ClearFormatting, CodeLine, CodeLineIndent, Column, ColumnResize, Columns, ColumnsResize, DOCUMENT_CLASS, DOCUMENT_TAGS, DUAL_BACKGROUND_MIN_RATIO, DUAL_CONTRAST_DARK, DUAL_CONTRAST_LIGHT, DUAL_CONTRAST_MIN_RATIO, Divider, Document$1 as Document, DocumentStyles, EMAIL_ATTRIBUTES, EMAIL_CSS_PROPERTIES, EMAIL_SAFE_STYLE_PROPERTIES, EMAIL_SAFE_TAGS, EMAIL_TAGS, EMAIL_TAG_ATTRIBUTES, EmailParagraph, FILE_CHOOSER_POINTER_WAIT, FILL_TEXT_COLOR, FILL_TEXT_COLOR_LIGHT, FILL_TEXT_COLOR_RGB, FOLD_WIDTH, FORMAT_WIDTH, GMAIL_CLIP_BYTES, GUIDES_ACTIVE_CLASS, GUIDES_PEEK_CLASS, GUIDES_PEEK_DELAY_MS, Gapcursor, HEADING_SIZES, HardBreak, Heading, History, HtmlComment, HtmlCommentInline, HtmlElement, HtmlInline, HtmlLanguage, HtmlRaw, HtmlTextElement, HtmlVoid, HtmlVoidBlock, IMPORT_VIEWPORT_WIDTH, INDENT_MAX, INDENT_STEP, INLINE_TAGS, INLINE_VOID_TAGS, IN_SELECTION_CLASS, Image, InlineAtomSelection, InlineImageStore, InlineImages, Italic, LIST_STYLE, LayoutGuides, Link, ListItem, MAX_COLUMNS, MAX_IMAGE_WIDTH, MAX_MERGE_TAG_LENGTH, MAX_UNBROKEN_RUN, MIN_COLUMN_CAP, MIN_COLUMN_PCT, MIN_FONT_SIZE, MIN_IMAGE_WIDTH, MIN_TABLE_PCT, MJML_WORLDLY_HTML, MergeTag, NoTextDrag, OrderedList, PARSE_SCOPE_KEY, PLACEHOLDER_WIDTH, Paragraph, PasteHygiene, QuotedHistory, REFUSED_TAGS, RENDERING_CLIENTS, SECTION_CONTENT_MAX, SECTION_INSET, SECTION_PADDING, STACK_CLASS, STACK_RULE, Section, SplitKeepingMarks, TABLE_BORDER_COLOR, TABLE_CELL_PADDING, TABLE_SECTION_TAGS, TYPING_REST, Table, TableCell, TableRow, Text, TextStyle, UNSET_BUTTON_HREF, Underline, VOID_TAGS, acceptProposal, addColumn, addColumnAtEnd, addRowAtEnd, analyzeAngularExpression, angularDialect, angularRequiredFields, applyAuthoredAttributes, applyEmailVocabulary, attributeString, authoredAttribute, authoredMarkupOf, authoredViewAttributes, bareButtons, buttonStyle, canonicalHead, canonicalMergeTagInner, canonicalRender, caretCellPos, caretInsideMergeTag, claimedImageFiles, clearCells, clientList, columnCaps, columnWidths, completionContextAt, containerStyle, contrastRatio, correctStoredMistakes, createAngularExpressions, createBlockMenu, createBubbleMenu, createButtonEdit, createContentProposal, createContentStream, createDOMParser, createEditor, createHtmlAutocomplete, createHtmlLanguage, createImageDrag, createInlineImages, createMergeTagResolution, createOffsetMapper, createQuotedHistory, createSchema, createSendIntent, createSourceMarks, createSuggestionMenu, createTableHandles, declarationProperty, declaredBackground, decodeDataUrl, defaultBubbleShouldShow, defineExtension, defineMark, defineNode, deleteColumns, deleteFullySelected, discardProposal, distributePadding, docText, dropDeadOfficeClasses, dropHidden, dropMediaQueries, dropZeroSizedWhitespace, duplicateColumn, duplicateRow, editQuotedHistory, effectiveWidths, emailBackgroundPalette, emailDocument, emailExtensions, emailPlainText, emailSizeBudget, emailTextPalette, embedsAsLinks, entitySpans, escapeAttribute$2 as escapeAttribute, escapeText$1 as escapeText, expressionDialect, expressionDialectKey, extensionActions, extensionSuggestions, fillTextColor, filledPlaceholderAttrs, filterEmailStyle, findColumnContext, findColumnsContext, findCssIssues, findListDepth, findSectionContext, findTableContext, fitImageWidth, foldHTML, formatHTML, formatPct, forwardDocument, forwardQuote, hasBlockChildren$1 as hasBlockChildren, hasDocumentEnvelope, headingStyle, holdsBlock, holdsColumn, hrefProblem, htmlSourceExtensions, imageDropTarget, importLoss, importedDocument, inheritTextStyles, inheritedMarkup, inlineBootstrapTableBorders, inlineImageCids, inlineImageRegistry, inlineImagesKey, inlineStyles, insertHTML, insertMergeTag, isActionEnabled, isBlock$1 as isBlock, isBlockLevel, isBlockish, isBooleanAttribute, isEmailAttribute, isEmailCssProperty, isEmailTag, isFillTextColor, isInlineAtom, isMarkActive, isMergeTagExpression, isMergeTagPath, isNodeActive, isPadded, isProposing, isQuotedHistoryFolded, isSafeColor, isSafeFontFamily, isSafeFontSize, isSafeUrl$1 as isSafeUrl, isSectionImageUrl, isStreaming, italicStarInputRegex, italicStarPasteRegex, italicUnderscoreInputRegex, italicUnderscorePasteRegex, keepGmailRules, layoutBlockAt, linkClickPlugin, linkPastePlugin, linkRangeAt, lintHTML, lowerInlinesAroundBlocks, markAttrsOf, markStackingColumns, marksAcrossBreak, materializeComments, measureMenuPlacement, mediaMatches, mergeTagAt, mergeTagExpressions, mergeTagFields, mergeTagRanges, mergeTagResolutionPending, moveColumn, moveRow, normalizeCommentText, normalizeCss, normalizeHref, normalizeMergeTagText, noteOwnWidths, openFileChooser, openTag$1 as openTag, openTags, outlookColumns, paddingOf, parseAngularExpression, parseDocument, parseFontFamily, parseFontSize, parseHTML, parsePadding, parseRules, parseTextTransform, passesDualBackground, passesDualContrast, preserveExtensions, preservedAttributes, promoteInlineImages, promoteMergeTags, proposalRange, proposeContent, quotedHistory, readEnvelope, readImageFile, realizeComments, relativeLuminance, removeColumn, removeQuotedHistory, renderForClient, renderedPath, repairLinkSchemes, repairTables, replaceHTML, replyDocument, replyEnvelope, replyQuote, reviseProposal, rewriteInlineImageSources, richTextExtensions, ruleForScope, ruleScope, sanitizePastedHTML, scanHTML, scanMergeTags, scopeOf$1 as scopeOf, scopedDocumentCss, selectColumn, selectRow, selectedButton, selectedImage, selectedImageAlt, selectedMarkAtom, selectionInsideMergeTag, serializeDocument, serializeToHTML, setCellBackground, setColumnBackground, setColumnBoundary, setColumnsBoundary, setQuotedHistory, setSectionBackground, setSectionImage, setTableBox, setTableWidth, soleInlineAtom, splitDeclarations$2 as splitDeclarations, splitListItemKeepMarks, starInputRegex, starPasteRegex, stopProposal, streamContent, streamedRange, streamingRange, suggestionSectionTitles, tableStyle, textOffsetAt, textRegions, toEmailSafeColor, toInboundMessage, toggleList, trimInlineBoxes, underscoreInputRegex, underscorePasteRegex, unwrapLayoutTables, unwrapOfficeParagraphMarks, verbatimElement, videoPage, watchMenuScroll, withAttribute, withAuthoredMarkup, withQuoted, withQuotedHistory, withStyleDeclaration, withoutAttribute, withoutStyleDeclaration };
18820
18785
  //# sourceMappingURL=h-k-dev-angular-email-editor.mjs.map