@h-k-dev/angular-email-editor 0.0.4 → 0.0.5
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/fesm2022/h-k-dev-angular-email-editor-suggestion-menu.mjs +20 -1
- package/fesm2022/h-k-dev-angular-email-editor-suggestion-menu.mjs.map +1 -1
- package/fesm2022/h-k-dev-angular-email-editor.mjs +332 -90
- package/fesm2022/h-k-dev-angular-email-editor.mjs.map +1 -1
- package/package.json +1 -1
- package/types/h-k-dev-angular-email-editor.d.ts +65 -18
|
@@ -2231,11 +2231,12 @@ function tokens(value) {
|
|
|
2231
2231
|
* engine handles both — so merged cells are a real feature here, and imported
|
|
2232
2232
|
* mail keeps its shape instead of being flattened.
|
|
2233
2233
|
*/
|
|
2234
|
-
// The
|
|
2235
|
-
//
|
|
2236
|
-
//
|
|
2237
|
-
//
|
|
2238
|
-
//
|
|
2234
|
+
// The table element itself carries no border or padding — those are per cell
|
|
2235
|
+
// (`border` and `padding` attrs, which is what tells the three `TableKind`s
|
|
2236
|
+
// apart). The faint grid shown while editing is an editor-only aid (the
|
|
2237
|
+
// layout-guide rules in the app's global styles), not part of the email.
|
|
2238
|
+
// Preset padding is a fixed, modest value (horizontal padding eats a phone's
|
|
2239
|
+
// width).
|
|
2239
2240
|
// `table-layout: fixed` is the difference between a table you can type in and
|
|
2240
2241
|
// one that jumps: without it, column widths are computed from *content*, so
|
|
2241
2242
|
// every keystroke re-lays out the whole grid and the column you are typing in
|
|
@@ -2253,19 +2254,23 @@ function tokens(value) {
|
|
|
2253
2254
|
40% of the container, in every client and in the editor alike). The
|
|
2254
2255
|
offset serializes as `margin-left` — inline margins on tables are what
|
|
2255
2256
|
Outlook's own Word composer emits, so its engine reads them, and a client
|
|
2256
|
-
that strips them degrades the table gracefully to left-aligned.
|
|
2257
|
-
|
|
2257
|
+
that strips them degrades the table gracefully to left-aligned.
|
|
2258
|
+
`spacing` (px, or null for none) is the room above and below the table —
|
|
2259
|
+
`margin-top`/`margin-bottom`, block only, never the sides: real space
|
|
2260
|
+
between the table and the lines of text around it, which a client that
|
|
2261
|
+
strips it degrades to a table flush against its neighbours. */
|
|
2262
|
+
const tableStyle = (width, offset, spacing = null) => `width: ${formatPct(width)};` +
|
|
2258
2263
|
(offset > 0 ? ` margin-left: ${formatPct(offset)};` : '') +
|
|
2264
|
+
(spacing ? ` margin-top: ${spacing}px; margin-bottom: ${spacing}px;` : '') +
|
|
2259
2265
|
' table-layout: fixed; border-collapse: collapse;';
|
|
2260
2266
|
// Fixed layout means a long unbroken word can no longer widen its column, so it
|
|
2261
2267
|
// would spill out of the cell instead. The editor never showed that (the
|
|
2262
2268
|
// editable root sets `word-wrap` for its own reasons, and it inherits), which
|
|
2263
2269
|
// is exactly why it has to be said out loud here — otherwise the overflow shows
|
|
2264
2270
|
// up only in the recipient's client.
|
|
2265
|
-
// No padding here: the email carries only
|
|
2266
|
-
//
|
|
2267
|
-
//
|
|
2268
|
-
// sees — so it can also reserve the room the block affordances live in.
|
|
2271
|
+
// No padding here: the email carries only the cell's own `padding` attr
|
|
2272
|
+
// (authored, or a bordered/borderless preset's), and the editor draws exactly
|
|
2273
|
+
// that — it adds no cell spacing of its own.
|
|
2269
2274
|
const cellStyle = (valign) => `vertical-align: ${valign}; overflow-wrap: break-word;`;
|
|
2270
2275
|
/** A cell's horizontal alignment off parsed markup: the inline style first,
|
|
2271
2276
|
then the legacy `align` attribute — the pair real mail is written with,
|
|
@@ -2310,13 +2315,15 @@ function parsePadding(dom) {
|
|
|
2310
2315
|
`<td>` is the bulletproof border in email — Outlook's Word engine renders
|
|
2311
2316
|
it), with `border-collapse` on the table keeping the grid single-lined. */
|
|
2312
2317
|
const TABLE_BORDER_COLOR = 'rgb(208, 215, 229)';
|
|
2313
|
-
/** The
|
|
2314
|
-
the rendered email is readable
|
|
2315
|
-
|
|
2316
|
-
table td` rule): a bordered and a plain table feel identical while
|
|
2317
|
-
composing; only what the recipient gets differs — the preset ships its
|
|
2318
|
-
padding, the plain table ships none unless authored. */
|
|
2318
|
+
/** The *real* cell padding a bordered or borderless table ships —
|
|
2319
|
+
Excel-style breathing room, so the rendered email is readable. A layout
|
|
2320
|
+
table ships none unless authored, and is drawn flush in the editor too. */
|
|
2319
2321
|
const TABLE_CELL_PADDING = '8px 12px';
|
|
2322
|
+
/** The room a bordered or borderless table keeps above and below itself, in
|
|
2323
|
+
px — real (`margin-top`/`margin-bottom` on the table, see `tableStyle`),
|
|
2324
|
+
so the email sets the table off from the text around it exactly as the
|
|
2325
|
+
editor does. Block only: the sides stay on the text column. */
|
|
2326
|
+
const TABLE_BLOCK_SPACING = 16;
|
|
2320
2327
|
/** Canonical percentage: one decimal at most, no trailing zero (25%, 33.3%). */
|
|
2321
2328
|
const formatPct = (n) => `${Math.round(n * 10) / 10}%`;
|
|
2322
2329
|
/** No column below 10%: at 320px that is ~32px — the width where a column
|
|
@@ -2341,7 +2348,18 @@ function pctOf(raw) {
|
|
|
2341
2348
|
function parseTableBox(dom) {
|
|
2342
2349
|
const width = Math.min(Math.max(pctOf(dom.style?.width || dom.getAttribute('width') || '') ?? 100, MIN_TABLE_PCT), 100);
|
|
2343
2350
|
const offset = Math.min(Math.max(pctOf(dom.style?.marginLeft || '') ?? 0, 0), 100 - width);
|
|
2344
|
-
return { width, offset };
|
|
2351
|
+
return { width, offset, spacing: parseBlockSpacing(dom) };
|
|
2352
|
+
}
|
|
2353
|
+
/** The room above and below a table off parsed markup: px, the same above as
|
|
2354
|
+
below — the one shape `tableStyle` writes. Anything else (one side only,
|
|
2355
|
+
em, %, `auto`) is not a look this schema sells, and repairs to none. */
|
|
2356
|
+
function parseBlockSpacing(dom) {
|
|
2357
|
+
const top = (dom.style?.marginTop || '').trim();
|
|
2358
|
+
if (top !== (dom.style?.marginBottom || '').trim())
|
|
2359
|
+
return null;
|
|
2360
|
+
const match = /^(\d+(?:\.\d+)?)px$/.exec(top);
|
|
2361
|
+
const spacing = match ? Number.parseFloat(match[1]) : 0;
|
|
2362
|
+
return spacing > 0 ? spacing : null;
|
|
2345
2363
|
}
|
|
2346
2364
|
/** A `colspan`/`rowspan` off parsed markup: 1 when absent, malformed, zero or
|
|
2347
2365
|
negative — real mail carries all of those, and the grid must stay sane. */
|
|
@@ -2454,12 +2472,14 @@ const TableCell = defineNode({
|
|
|
2454
2472
|
// Same attr name the library's commands expect, different unit on
|
|
2455
2473
|
// purpose; pixel widths never parse in (see the node docs).
|
|
2456
2474
|
colwidth: { default: null },
|
|
2457
|
-
//
|
|
2458
|
-
//
|
|
2475
|
+
// Real padding (px, via `parsePadding`): authored, or the bordered and
|
|
2476
|
+
// borderless presets' `TABLE_CELL_PADDING`. `null` — the default, and a
|
|
2477
|
+
// layout table's — serializes none, and the editor draws none. Cells added to a uniformly padded table inherit
|
|
2478
|
+
// it (see `unifyCellPresets`).
|
|
2459
2479
|
padding: { default: null },
|
|
2460
2480
|
// The cell's grid-line colour (`border: 1px solid <color>`), or null
|
|
2461
|
-
// for
|
|
2462
|
-
//
|
|
2481
|
+
// for no line. Set for every cell of a bordered insert (`/table`); kept
|
|
2482
|
+
// uniform by the repair plugin (see `unifyCellPresets`).
|
|
2463
2483
|
border: { default: null },
|
|
2464
2484
|
// A fill colour on the cell (the most bulletproof background in email —
|
|
2465
2485
|
// `background-color` on `<td>` renders even in Outlook). From the curated
|
|
@@ -2510,7 +2530,9 @@ const Table = defineNode({
|
|
|
2510
2530
|
allowGapCursor: false,
|
|
2511
2531
|
// Width and left offset in percent of the container; the defaults
|
|
2512
2532
|
// (100, 0) serialize identically to the pre-attr canonical form.
|
|
2513
|
-
|
|
2533
|
+
// `spacing`: px of room above and below (`TABLE_BLOCK_SPACING` for the
|
|
2534
|
+
// bordered and borderless kinds), null — the default — for none.
|
|
2535
|
+
attrs: { width: { default: 100 }, offset: { default: 0 }, spacing: { default: null } },
|
|
2514
2536
|
parseDOM: [{ tag: 'table', getAttrs: (dom) => parseTableBox(dom) }],
|
|
2515
2537
|
// <tbody> wrapper matches what mail clients expect and what the HTML
|
|
2516
2538
|
// parser re-injects, so serialize → parse → serialize is a fixpoint.
|
|
@@ -2521,14 +2543,15 @@ const Table = defineNode({
|
|
|
2521
2543
|
'table',
|
|
2522
2544
|
{
|
|
2523
2545
|
role: 'presentation',
|
|
2524
|
-
style: tableStyle(node.attrs['width'], node.attrs['offset']),
|
|
2546
|
+
style: tableStyle(node.attrs['width'], node.attrs['offset'], node.attrs['spacing']),
|
|
2525
2547
|
},
|
|
2526
2548
|
['tbody', 0],
|
|
2527
2549
|
],
|
|
2528
2550
|
},
|
|
2529
2551
|
commands: ({ schema }) => ({
|
|
2530
|
-
/** The default shape
|
|
2531
|
-
|
|
2552
|
+
/** The default shape and kind are the ones /table inserts — three rows
|
|
2553
|
+
by two, bordered (see `TableKind`). */
|
|
2554
|
+
insertTable: (rows = 3, cols = 2, kind = 'bordered') => insertTableFocused(schema, rows, cols, kind),
|
|
2532
2555
|
// Selection-relative structure edits, straight from the library: each one
|
|
2533
2556
|
// understands merged cells and multi-cell selections for free. The
|
|
2534
2557
|
// add-column pair is wrapped: on a table with declared widths, the library
|
|
@@ -2668,15 +2691,15 @@ const Table = defineNode({
|
|
|
2668
2691
|
// a rectangle. Covers everything that reaches the editor as a transaction
|
|
2669
2692
|
// — paste, drops, `setContent`, an import landing on the html signal —
|
|
2670
2693
|
// while `repairTables` covers the pure parse path (see `html.ts`).
|
|
2671
|
-
// `
|
|
2672
|
-
// arrive with
|
|
2694
|
+
// `unifyCellPresets` rides the same pass: cells that structural edits add
|
|
2695
|
+
// arrive with a null border and padding and inherit a uniform table's.
|
|
2673
2696
|
new Plugin({
|
|
2674
2697
|
key: new PluginKey('tableRepair'),
|
|
2675
2698
|
appendTransaction: (transactions, oldState, newState) => {
|
|
2676
2699
|
if (!transactions.some((tr) => tr.docChanged))
|
|
2677
2700
|
return undefined;
|
|
2678
2701
|
const tr = fixTables(newState, oldState) ?? newState.tr;
|
|
2679
|
-
|
|
2702
|
+
unifyCellPresets(tr, insertedRanges([...transactions, tr]));
|
|
2680
2703
|
return tr.docChanged ? tr : undefined;
|
|
2681
2704
|
},
|
|
2682
2705
|
}),
|
|
@@ -2687,23 +2710,32 @@ const Table = defineNode({
|
|
|
2687
2710
|
// Three rows by two: a table asked for by name starts with somewhere to
|
|
2688
2711
|
// write a heading line and two entries under it, which is what an email
|
|
2689
2712
|
// table almost always turns out to be. A picker (the app's grid) says its
|
|
2690
|
-
// own size; this is only what `/table` means on its own.
|
|
2713
|
+
// own size; this is only what `/table` means on its own. One item per
|
|
2714
|
+
// `TableKind`, the bordered default first.
|
|
2691
2715
|
actions: ({ schema }) => [
|
|
2692
2716
|
{
|
|
2693
2717
|
id: 'table',
|
|
2694
2718
|
section: 'layout',
|
|
2695
2719
|
title: 'Table',
|
|
2696
|
-
keywords: ['table', 'grid', 'rows', 'columns'],
|
|
2697
|
-
icon: '
|
|
2698
|
-
command: insertTableFocused(schema, 3, 2),
|
|
2720
|
+
keywords: ['table', 'bordered', 'grid', 'rows', 'columns', 'excel', 'lines'],
|
|
2721
|
+
icon: 'grid_on',
|
|
2722
|
+
command: insertTableFocused(schema, 3, 2, 'bordered'),
|
|
2699
2723
|
},
|
|
2700
2724
|
{
|
|
2701
|
-
id: '
|
|
2725
|
+
id: 'borderless-table',
|
|
2702
2726
|
section: 'layout',
|
|
2703
|
-
title: '
|
|
2704
|
-
keywords: ['
|
|
2705
|
-
icon: '
|
|
2706
|
-
command: insertTableFocused(schema, 3, 2,
|
|
2727
|
+
title: 'Borderless table',
|
|
2728
|
+
keywords: ['borderless-table', 'table', 'borderless', 'no lines', 'padding'],
|
|
2729
|
+
icon: 'border_clear',
|
|
2730
|
+
command: insertTableFocused(schema, 3, 2, 'borderless'),
|
|
2731
|
+
},
|
|
2732
|
+
{
|
|
2733
|
+
id: 'layout-table',
|
|
2734
|
+
section: 'layout',
|
|
2735
|
+
title: 'Layout table',
|
|
2736
|
+
keywords: ['layout-table', 'table', 'layout', 'invisible', 'side by side'],
|
|
2737
|
+
icon: 'view_quilt',
|
|
2738
|
+
command: insertTableFocused(schema, 3, 2, 'layout'),
|
|
2707
2739
|
},
|
|
2708
2740
|
],
|
|
2709
2741
|
});
|
|
@@ -2729,13 +2761,13 @@ function setCellBackground(color) {
|
|
|
2729
2761
|
/** Inserts a table and drops the cursor into its first cell. The table is
|
|
2730
2762
|
located after insertion (rather than by fragile nodeSize math) and
|
|
2731
2763
|
`cellStart` resolves the exact text position inside cell (0, 0). */
|
|
2732
|
-
function insertTableFocused(schema, rows, cols,
|
|
2764
|
+
function insertTableFocused(schema, rows, cols, kind) {
|
|
2733
2765
|
return (state, dispatch) => {
|
|
2734
2766
|
// Asked, not told: answer before building anything — a toolbar asks on
|
|
2735
2767
|
// every transaction.
|
|
2736
2768
|
if (!dispatch)
|
|
2737
2769
|
return true;
|
|
2738
|
-
const table = buildTable(schema, rows, cols,
|
|
2770
|
+
const table = buildTable(schema, rows, cols, kind);
|
|
2739
2771
|
const from = state.selection.from;
|
|
2740
2772
|
const tr = state.tr.replaceSelectionWith(table);
|
|
2741
2773
|
let tablePos = -1;
|
|
@@ -3071,49 +3103,90 @@ function isColumnBoundaryClean(map, index) {
|
|
|
3071
3103
|
}
|
|
3072
3104
|
return true;
|
|
3073
3105
|
}
|
|
3074
|
-
function buildTable(schema, rows, cols,
|
|
3106
|
+
function buildTable(schema, rows, cols, kind) {
|
|
3075
3107
|
const cellType = schema.nodes['tableCell'];
|
|
3076
3108
|
const rowType = schema.nodes['tableRow'];
|
|
3077
3109
|
const tableType = schema.nodes['table'];
|
|
3078
|
-
//
|
|
3079
|
-
//
|
|
3080
|
-
const attrs = {
|
|
3110
|
+
// Bordered and borderless ship real padding (TABLE_CELL_PADDING); a layout
|
|
3111
|
+
// table ships none — its spacing is the editor's alone.
|
|
3112
|
+
const attrs = {
|
|
3113
|
+
border: kind === 'bordered' ? TABLE_BORDER_COLOR : null,
|
|
3114
|
+
padding: kind === 'layout' ? null : TABLE_CELL_PADDING,
|
|
3115
|
+
};
|
|
3081
3116
|
const makeRow = () => rowType.create(null, Array.from({ length: cols }, () => cellType.createAndFill(attrs)));
|
|
3082
|
-
return tableType.create(null, Array.from({ length: rows }, makeRow));
|
|
3117
|
+
return tableType.create({ spacing: kind === 'layout' ? null : TABLE_BLOCK_SPACING }, Array.from({ length: rows }, makeRow));
|
|
3118
|
+
}
|
|
3119
|
+
/** The ranges of the final document that the steps of `trs` (applied one
|
|
3120
|
+
after another) inserted — what is *new* in it. Earlier ranges are mapped
|
|
3121
|
+
through every later step, so all of them speak the last doc's positions. */
|
|
3122
|
+
function insertedRanges(trs) {
|
|
3123
|
+
let ranges = [];
|
|
3124
|
+
for (const tr of trs) {
|
|
3125
|
+
for (const map of tr.mapping.maps) {
|
|
3126
|
+
ranges = ranges.map(([from, to]) => [map.map(from, -1), map.map(to, 1)]);
|
|
3127
|
+
map.forEach((_oldStart, _oldEnd, newStart, newEnd) => {
|
|
3128
|
+
if (newEnd > newStart)
|
|
3129
|
+
ranges.push([newStart, newEnd]);
|
|
3130
|
+
});
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
return ranges;
|
|
3083
3134
|
}
|
|
3084
3135
|
/**
|
|
3085
|
-
* Keeps a
|
|
3086
|
-
*
|
|
3087
|
-
*
|
|
3088
|
-
*
|
|
3089
|
-
*
|
|
3090
|
-
*
|
|
3091
|
-
*
|
|
3136
|
+
* Keeps a preset table uniform: `addRow`/`addColumn`/the pills/Tab past the
|
|
3137
|
+
* end all create cells with a null `border` and `padding`, which would leave
|
|
3138
|
+
* a bordered or borderless table with cells the email draws differently from
|
|
3139
|
+
* their neighbours.
|
|
3140
|
+
*
|
|
3141
|
+
* - **Border**: when every bordered cell wears the same colour, the bare
|
|
3142
|
+
* cells inherit it. Mixed colours (authored, imported) stay as written.
|
|
3143
|
+
* - **Padding**: stricter — only cells *this transaction added* to a table
|
|
3144
|
+
* that was *already there* inherit a uniform padding. Real mail pads a
|
|
3145
|
+
* spacer cell here and there, and an import must not spread that over
|
|
3146
|
+
* every cell: repair, not opinion.
|
|
3147
|
+
*
|
|
3148
|
+
* `setNodeMarkup` never changes node sizes, so positions collected up front
|
|
3149
|
+
* stay valid as the jobs apply.
|
|
3092
3150
|
*/
|
|
3093
|
-
function
|
|
3151
|
+
function unifyCellPresets(tr, inserted) {
|
|
3152
|
+
const isNew = (from, to) => inserted.some(([f, t]) => f <= from && to <= t);
|
|
3094
3153
|
const jobs = [];
|
|
3095
3154
|
tr.doc.descendants((node, pos) => {
|
|
3096
3155
|
if (node.type.name !== 'table')
|
|
3097
3156
|
return true;
|
|
3098
|
-
const
|
|
3099
|
-
|
|
3157
|
+
const borders = new Set();
|
|
3158
|
+
const paddings = new Set();
|
|
3159
|
+
let unbordered = 0;
|
|
3100
3160
|
node.descendants((cell) => {
|
|
3101
3161
|
if (cell.type.name !== 'tableCell')
|
|
3102
3162
|
return true;
|
|
3103
3163
|
const border = cell.attrs['border'];
|
|
3164
|
+
const padding = cell.attrs['padding'];
|
|
3104
3165
|
if (border)
|
|
3105
|
-
|
|
3166
|
+
borders.add(border);
|
|
3106
3167
|
else
|
|
3107
|
-
|
|
3108
|
-
|
|
3168
|
+
unbordered++;
|
|
3169
|
+
if (padding)
|
|
3170
|
+
paddings.add(padding);
|
|
3171
|
+
return false;
|
|
3109
3172
|
});
|
|
3110
|
-
|
|
3111
|
-
|
|
3173
|
+
const border = borders.size === 1 && unbordered > 0 ? [...borders][0] : null;
|
|
3174
|
+
const padding = paddings.size === 1 && !isNew(pos, pos + node.nodeSize) ? [...paddings][0] : null;
|
|
3175
|
+
if (border || padding) {
|
|
3112
3176
|
node.descendants((cell, rel) => {
|
|
3113
|
-
if (cell.type.name
|
|
3114
|
-
|
|
3177
|
+
if (cell.type.name !== 'tableCell')
|
|
3178
|
+
return true;
|
|
3179
|
+
const at = pos + 1 + rel;
|
|
3180
|
+
const attrs = { ...cell.attrs };
|
|
3181
|
+
if (border && !attrs['border'])
|
|
3182
|
+
attrs['border'] = border;
|
|
3183
|
+
if (padding && !attrs['padding'] && isNew(at, at + cell.nodeSize)) {
|
|
3184
|
+
attrs['padding'] = padding;
|
|
3115
3185
|
}
|
|
3116
|
-
|
|
3186
|
+
if (attrs['border'] !== cell.attrs['border'] || attrs['padding'] !== cell.attrs['padding']) {
|
|
3187
|
+
jobs.push({ pos: at, attrs });
|
|
3188
|
+
}
|
|
3189
|
+
return false;
|
|
3117
3190
|
});
|
|
3118
3191
|
}
|
|
3119
3192
|
return false; // cells handled; nothing tabular nests deeper
|
|
@@ -5548,7 +5621,9 @@ const Columns = defineNode({
|
|
|
5548
5621
|
insertColumns: (count = 2) => insertColumns(schema, count),
|
|
5549
5622
|
/** Fill the column the cursor is in (or clear it with `null`). */
|
|
5550
5623
|
setColumnBackground: (color) => setColumnBackground(color),
|
|
5551
|
-
//
|
|
5624
|
+
// Caret-relative structural edits, for a host's own controls (the
|
|
5625
|
+
// block's pills use the position-addressed `appendColumn` /
|
|
5626
|
+
// `removeLastColumn`). Named apart from the table's
|
|
5552
5627
|
// `addColumnAfter`/`deleteColumn` — commands merge into one flat record.
|
|
5553
5628
|
addColumn: () => addColumn,
|
|
5554
5629
|
removeColumn: () => removeColumn,
|
|
@@ -5568,12 +5643,17 @@ const Columns = defineNode({
|
|
|
5568
5643
|
// column's edge hops straight into the neighbouring column — the layout
|
|
5569
5644
|
// twin of the table's cell-to-cell arrows. Mod-A is the table's scoped
|
|
5570
5645
|
// select-all applied here: column content first, block from an empty
|
|
5571
|
-
// column, the stock whole-document one from the block selection on.
|
|
5646
|
+
// column, the stock whole-document one from the block selection on. And
|
|
5647
|
+
// Delete over whole columns removes them — the block's only delete.
|
|
5572
5648
|
plugins: () => [
|
|
5573
5649
|
keymap({
|
|
5574
5650
|
ArrowLeft: columnArrow(-1),
|
|
5575
5651
|
ArrowRight: columnArrow(1),
|
|
5576
5652
|
'Mod-a': selectColumnContent,
|
|
5653
|
+
Backspace: deleteFullySelectedColumns,
|
|
5654
|
+
'Mod-Backspace': deleteFullySelectedColumns,
|
|
5655
|
+
Delete: deleteFullySelectedColumns,
|
|
5656
|
+
'Mod-Delete': deleteFullySelectedColumns,
|
|
5577
5657
|
}),
|
|
5578
5658
|
],
|
|
5579
5659
|
actions: ({ schema }) => [
|
|
@@ -5604,6 +5684,16 @@ function hasColumnChildren(dom) {
|
|
|
5604
5684
|
}
|
|
5605
5685
|
return false;
|
|
5606
5686
|
}
|
|
5687
|
+
/** How many empty lines a fresh column starts with. Two, not one: the block
|
|
5688
|
+
has no padding of the editor's own, so a one-line column is a sliver the
|
|
5689
|
+
eye reads as a stray rule rather than a place to write — two lines give
|
|
5690
|
+
it the shape of a column, the way /table starts with rows to fill. */
|
|
5691
|
+
const COLUMN_STARTING_LINES = 2;
|
|
5692
|
+
/** An empty column, {@link COLUMN_STARTING_LINES} lines tall. */
|
|
5693
|
+
function freshColumn(schema, attrs = null) {
|
|
5694
|
+
const lines = Array.from({ length: COLUMN_STARTING_LINES }, () => schema.nodes['paragraph'].createAndFill());
|
|
5695
|
+
return schema.nodes['column'].create(attrs, lines);
|
|
5696
|
+
}
|
|
5607
5697
|
/** Inserts an n-column block and drops the cursor into the first column. */
|
|
5608
5698
|
function insertColumns(schema, count) {
|
|
5609
5699
|
return (state, dispatch) => {
|
|
@@ -5611,10 +5701,9 @@ function insertColumns(schema, count) {
|
|
|
5611
5701
|
// every transaction.
|
|
5612
5702
|
if (!dispatch)
|
|
5613
5703
|
return true;
|
|
5614
|
-
const colType = schema.nodes['column'];
|
|
5615
5704
|
const columnsType = schema.nodes['columns'];
|
|
5616
5705
|
const maxWidth = columnMaxWidth(count);
|
|
5617
|
-
const columns = Array.from({ length: count }, () =>
|
|
5706
|
+
const columns = Array.from({ length: count }, () => freshColumn(schema, { maxWidth }));
|
|
5618
5707
|
const node = columnsType.create(null, columns);
|
|
5619
5708
|
const from = state.selection.from;
|
|
5620
5709
|
const tr = state.tr.replaceSelectionWith(node);
|
|
@@ -5721,9 +5810,7 @@ const addColumn = (state, dispatch) => {
|
|
|
5721
5810
|
const existing = [];
|
|
5722
5811
|
ctx.node.forEach((col) => existing.push(col));
|
|
5723
5812
|
const columns = resplitColumns(existing, count);
|
|
5724
|
-
const fresh = state.schema
|
|
5725
|
-
maxWidth: columnMaxWidth(count),
|
|
5726
|
-
});
|
|
5813
|
+
const fresh = freshColumn(state.schema, { maxWidth: columnMaxWidth(count) });
|
|
5727
5814
|
columns.splice(ctx.index + 1, 0, fresh);
|
|
5728
5815
|
const tr = state.tr.replaceWith(ctx.pos, ctx.pos + ctx.node.nodeSize, ctx.node.type.create(ctx.node.attrs, columns));
|
|
5729
5816
|
// The fresh column starts after the block's opening token (+1) and every
|
|
@@ -5764,6 +5851,107 @@ const deleteColumns = (state, dispatch) => {
|
|
|
5764
5851
|
dispatch?.(state.tr.delete(ctx.pos, ctx.pos + ctx.node.nodeSize).scrollIntoView());
|
|
5765
5852
|
return true;
|
|
5766
5853
|
};
|
|
5854
|
+
/** Restructures the columns block at `pos` in place: drops the columns
|
|
5855
|
+
`keep` refuses, optionally appends an empty one, and re-splits every cap
|
|
5856
|
+
evenly. Step by step — never a whole-block replace — so the selection
|
|
5857
|
+
maps through untouched: a caret in a kept column stays exactly where it
|
|
5858
|
+
was, one in a removed column lands at the nearest valid spot. The pills'
|
|
5859
|
+
and the select-to-delete gesture's shared tail. */
|
|
5860
|
+
function restructureColumns(state, pos, block, keep, append = false) {
|
|
5861
|
+
const tr = state.tr;
|
|
5862
|
+
const starts = [];
|
|
5863
|
+
let at = pos + 1;
|
|
5864
|
+
block.forEach((col) => {
|
|
5865
|
+
starts.push(at);
|
|
5866
|
+
at += col.nodeSize;
|
|
5867
|
+
});
|
|
5868
|
+
// Back to front, so the earlier starts stay valid.
|
|
5869
|
+
for (let index = block.childCount - 1; index >= 0; index--) {
|
|
5870
|
+
if (!keep(index))
|
|
5871
|
+
tr.delete(starts[index], starts[index] + block.child(index).nodeSize);
|
|
5872
|
+
}
|
|
5873
|
+
if (append) {
|
|
5874
|
+
const end = tr.mapping.map(pos + block.nodeSize - 1, -1);
|
|
5875
|
+
tr.insert(end, freshColumn(state.schema));
|
|
5876
|
+
}
|
|
5877
|
+
const rebuilt = tr.doc.nodeAt(pos);
|
|
5878
|
+
const maxWidth = columnMaxWidth(rebuilt.childCount);
|
|
5879
|
+
rebuilt.forEach((col, offset) => {
|
|
5880
|
+
tr.setNodeMarkup(pos + 1 + offset, undefined, { ...col.attrs, maxWidth });
|
|
5881
|
+
});
|
|
5882
|
+
return tr;
|
|
5883
|
+
}
|
|
5884
|
+
/** The `+` pill on the block's right flank: an empty column after the last,
|
|
5885
|
+
up to {@link MAX_COLUMNS}; every cap re-splits evenly. Addressed by the
|
|
5886
|
+
block's position, not the caret — the pill acts on the block it is on. */
|
|
5887
|
+
function appendColumn(pos) {
|
|
5888
|
+
return (state, dispatch) => {
|
|
5889
|
+
const block = state.doc.nodeAt(pos);
|
|
5890
|
+
if (block?.type.name !== 'columns' || block.childCount >= MAX_COLUMNS)
|
|
5891
|
+
return false;
|
|
5892
|
+
dispatch?.(restructureColumns(state, pos, block, () => true, true));
|
|
5893
|
+
return true;
|
|
5894
|
+
};
|
|
5895
|
+
}
|
|
5896
|
+
/** The `−` pill on the block's left flank: the last column goes — the `+`'s
|
|
5897
|
+
exact inverse — and the rest re-split evenly. Refuses on the last one
|
|
5898
|
+
left: the block itself goes by selecting it whole and pressing Delete. */
|
|
5899
|
+
function removeLastColumn(pos) {
|
|
5900
|
+
return (state, dispatch) => {
|
|
5901
|
+
const block = state.doc.nodeAt(pos);
|
|
5902
|
+
if (block?.type.name !== 'columns' || block.childCount <= 1)
|
|
5903
|
+
return false;
|
|
5904
|
+
dispatch?.(restructureColumns(state, pos, block, (index) => index < block.childCount - 1));
|
|
5905
|
+
return true;
|
|
5906
|
+
};
|
|
5907
|
+
}
|
|
5908
|
+
/**
|
|
5909
|
+
* Backspace/Delete with whole columns selected — the table's gesture on the
|
|
5910
|
+
* layout block: select a column's content end to end (Mod-A in it, or a
|
|
5911
|
+
* drag) and the column goes; select several whole columns and they go;
|
|
5912
|
+
* select every column and the block goes. Anything less falls through to
|
|
5913
|
+
* the ordinary delete, which clears the selected text.
|
|
5914
|
+
*/
|
|
5915
|
+
const deleteFullySelectedColumns = (state, dispatch) => {
|
|
5916
|
+
const selection = state.selection;
|
|
5917
|
+
if (!(selection instanceof TextSelection) || selection.empty)
|
|
5918
|
+
return false;
|
|
5919
|
+
const { $from, $to } = selection;
|
|
5920
|
+
let depth = -1;
|
|
5921
|
+
for (let d = $from.depth; d > 0; d--) {
|
|
5922
|
+
if ($from.node(d).type.name === 'columns') {
|
|
5923
|
+
depth = d;
|
|
5924
|
+
break;
|
|
5925
|
+
}
|
|
5926
|
+
}
|
|
5927
|
+
if (depth < 0 || $to.depth < depth || $to.before(depth) !== $from.before(depth))
|
|
5928
|
+
return false;
|
|
5929
|
+
const block = $from.node(depth);
|
|
5930
|
+
const pos = $from.before(depth);
|
|
5931
|
+
const first = $from.index(depth);
|
|
5932
|
+
const last = $to.index(depth);
|
|
5933
|
+
// Whole columns: the selection starts where the first column's text starts
|
|
5934
|
+
// and ends where the last column's text ends.
|
|
5935
|
+
const start = (index) => {
|
|
5936
|
+
let at = pos + 1;
|
|
5937
|
+
for (let i = 0; i < index; i++)
|
|
5938
|
+
at += block.child(i).nodeSize;
|
|
5939
|
+
return at;
|
|
5940
|
+
};
|
|
5941
|
+
const textStart = Selection.findFrom(state.doc.resolve(start(first) + 1), 1, true);
|
|
5942
|
+
const textEnd = Selection.findFrom(state.doc.resolve(start(last) + block.child(last).nodeSize - 1), -1, true);
|
|
5943
|
+
if (!textStart || !textEnd || $from.pos > textStart.from || $to.pos < textEnd.to)
|
|
5944
|
+
return false;
|
|
5945
|
+
if (!dispatch)
|
|
5946
|
+
return true;
|
|
5947
|
+
if (first === 0 && last === block.childCount - 1) {
|
|
5948
|
+
dispatch(state.tr.delete(pos, pos + block.nodeSize).scrollIntoView());
|
|
5949
|
+
return true;
|
|
5950
|
+
}
|
|
5951
|
+
const keep = (index) => index < first || index > last;
|
|
5952
|
+
dispatch(restructureColumns(state, pos, block, keep).scrollIntoView());
|
|
5953
|
+
return true;
|
|
5954
|
+
};
|
|
5767
5955
|
/**
|
|
5768
5956
|
* Tab / Shift-Tab inside a columns block: move to the next / previous column,
|
|
5769
5957
|
* and past the block's ends hand off to the surrounding blocks. Always claims
|
|
@@ -5862,7 +6050,12 @@ const selectColumnContent = (state, dispatch) => {
|
|
|
5862
6050
|
if (depth < 0)
|
|
5863
6051
|
return false;
|
|
5864
6052
|
const column = $from.node(depth);
|
|
5865
|
-
|
|
6053
|
+
// Empty: nothing but blank lines (a fresh column has two).
|
|
6054
|
+
let empty = true;
|
|
6055
|
+
column.forEach((block) => {
|
|
6056
|
+
if (!block.isTextblock || block.childCount > 0)
|
|
6057
|
+
empty = false;
|
|
6058
|
+
});
|
|
5866
6059
|
if (dispatch) {
|
|
5867
6060
|
if (empty) {
|
|
5868
6061
|
dispatch(state.tr.setSelection(NodeSelection.create(state.doc, $from.before(depth - 1))));
|
|
@@ -13622,7 +13815,7 @@ class TableView {
|
|
|
13622
13815
|
this.#box = this.dom.appendChild(document.createElement('div'));
|
|
13623
13816
|
this.#box.className = 'aee-table-box';
|
|
13624
13817
|
this.#table = this.#box.appendChild(document.createElement('table'));
|
|
13625
|
-
this.#table.setAttribute('style', tableStyle(node.attrs['width'], node.attrs['offset']));
|
|
13818
|
+
this.#table.setAttribute('style', tableStyle(node.attrs['width'], node.attrs['offset'], node.attrs['spacing']));
|
|
13626
13819
|
this.#table.setAttribute('role', 'presentation');
|
|
13627
13820
|
this.#colgroup = this.#table.appendChild(document.createElement('colgroup'));
|
|
13628
13821
|
this.contentDOM = this.#table.appendChild(document.createElement('tbody'));
|
|
@@ -13752,7 +13945,7 @@ class TableView {
|
|
|
13752
13945
|
// is CSS-inset to the wrapper's content box (inside the editor-only
|
|
13753
13946
|
// gutter), so a child's `left` percentage is a share of the table's own
|
|
13754
13947
|
// area — table-relative shares are converted once, here.
|
|
13755
|
-
this.#table.setAttribute('style', tableStyle(tableWidth, offset));
|
|
13948
|
+
this.#table.setAttribute('style', tableStyle(tableWidth, offset, node.attrs['spacing']));
|
|
13756
13949
|
// An authored table (a template's, parsed in the `email` mode) shows its
|
|
13757
13950
|
// own attributes, as the email does — see authored.ts.
|
|
13758
13951
|
applyAuthoredAttributes(this.#table, node, 0);
|
|
@@ -13922,7 +14115,9 @@ class TableView {
|
|
|
13922
14115
|
rows are the same object (ProseMirror's persistent tree), so a keystroke
|
|
13923
14116
|
is one new cell and a handful of identity compares. */
|
|
13924
14117
|
function sameTableChrome(a, b) {
|
|
13925
|
-
if (a.attrs['width'] !== b.attrs['width'] ||
|
|
14118
|
+
if (a.attrs['width'] !== b.attrs['width'] ||
|
|
14119
|
+
a.attrs['offset'] !== b.attrs['offset'] ||
|
|
14120
|
+
a.attrs['spacing'] !== b.attrs['spacing']) {
|
|
13926
14121
|
return false;
|
|
13927
14122
|
}
|
|
13928
14123
|
if (a.childCount !== b.childCount)
|
|
@@ -14054,6 +14249,8 @@ class ColumnsView {
|
|
|
14054
14249
|
contentDOM;
|
|
14055
14250
|
#box;
|
|
14056
14251
|
#lines;
|
|
14252
|
+
#append;
|
|
14253
|
+
#remove;
|
|
14057
14254
|
#node;
|
|
14058
14255
|
#view;
|
|
14059
14256
|
#getPos;
|
|
@@ -14076,6 +14273,14 @@ class ColumnsView {
|
|
|
14076
14273
|
this.#lines.className = 'aee-col-lines';
|
|
14077
14274
|
this.#lines.contentEditable = 'false';
|
|
14078
14275
|
this.#lines.setAttribute('aria-hidden', 'true');
|
|
14276
|
+
// The block's two pills, the table's `+` turned into a stepper: `+` on
|
|
14277
|
+
// the right flank appends a column, `−` on the left takes the last one
|
|
14278
|
+
// away. Each sits in a sensor zone over the gutter beside the box — only
|
|
14279
|
+
// non-editable ground, so the zone can stay hit-testable and the pointer
|
|
14280
|
+
// never crosses dead space on its way over. No delete button: the block
|
|
14281
|
+
// goes the table's way, selected whole and Delete.
|
|
14282
|
+
this.#append = this.#pill('end', '+', 'Add column', appendColumn);
|
|
14283
|
+
this.#remove = this.#pill('start', '−', 'Remove last column', removeLastColumn);
|
|
14079
14284
|
this.#render(node);
|
|
14080
14285
|
}
|
|
14081
14286
|
update(node) {
|
|
@@ -14091,11 +14296,34 @@ class ColumnsView {
|
|
|
14091
14296
|
target === this.#box ||
|
|
14092
14297
|
target === this.#lines ||
|
|
14093
14298
|
this.#lines.contains(target) ||
|
|
14299
|
+
// The pills and their zones are ours too.
|
|
14300
|
+
(target instanceof Element && !!target.closest('.aee-add-zone')) ||
|
|
14094
14301
|
// The contentDOM's own attributes are ours; its children are ProseMirror's.
|
|
14095
14302
|
(target === this.contentDOM && record.type === 'attributes'));
|
|
14096
14303
|
}
|
|
14304
|
+
#pill(side, glyph, label, command) {
|
|
14305
|
+
const zone = this.#box.appendChild(document.createElement('div'));
|
|
14306
|
+
zone.className = `aee-add-zone aee-add-zone--${side}`;
|
|
14307
|
+
zone.contentEditable = 'false';
|
|
14308
|
+
zone.setAttribute('aria-hidden', 'true');
|
|
14309
|
+
const pill = zone.appendChild(document.createElement('div'));
|
|
14310
|
+
pill.className = `aee-add-pill aee-add-pill--${side}`;
|
|
14311
|
+
pill.textContent = glyph;
|
|
14312
|
+
pill.setAttribute('role', 'button');
|
|
14313
|
+
pill.setAttribute('title', label);
|
|
14314
|
+
// preventDefault keeps the caret where it is; the command runs on click.
|
|
14315
|
+
pill.addEventListener('mousedown', (event) => event.preventDefault());
|
|
14316
|
+
pill.addEventListener('click', () => {
|
|
14317
|
+
command(this.#getPos())(this.#view.state, this.#view.dispatch);
|
|
14318
|
+
});
|
|
14319
|
+
return pill;
|
|
14320
|
+
}
|
|
14097
14321
|
#render(node) {
|
|
14098
14322
|
this.#box.setAttribute('style', containerStyle(node.attrs['align']));
|
|
14323
|
+
// A pill with nothing to do says so: no `+` past the most columns, no
|
|
14324
|
+
// `−` on the last one.
|
|
14325
|
+
this.#append.toggleAttribute('data-disabled', node.childCount >= MAX_COLUMNS);
|
|
14326
|
+
this.#remove.toggleAttribute('data-disabled', node.childCount <= 1);
|
|
14099
14327
|
// An authored columns block shows its own attributes (authored.ts).
|
|
14100
14328
|
applyAuthoredAttributes(this.#box, node, 0);
|
|
14101
14329
|
const caps = columnCaps(node);
|
|
@@ -17300,29 +17528,43 @@ function discardTransaction(view) {
|
|
|
17300
17528
|
/**
|
|
17301
17529
|
* Where a floating menu goes for an anchor line: under it, clamped to its
|
|
17302
17530
|
* scroll container, flipped above when below would overflow the visible
|
|
17303
|
-
* area.
|
|
17304
|
-
*
|
|
17305
|
-
*
|
|
17531
|
+
* area. When it fits on neither side it goes to the side with more room and
|
|
17532
|
+
* says how tall it may be there (`maxHeight`) — flip, then size, as Floating
|
|
17533
|
+
* UI does — so the container never clips it.
|
|
17534
|
+
*
|
|
17535
|
+
* Read-only — it measures and returns, and the caller writes `left` / `top`
|
|
17536
|
+
* (and the height cap) in its own write phase, so measuring never follows a
|
|
17537
|
+
* write in the same task. The element must be `position: absolute` inside a
|
|
17306
17538
|
* `position: relative` scroll container; its size is read as rendered, so
|
|
17307
|
-
* call it after its contents are in.
|
|
17539
|
+
* call it after its contents are in. A caller that caps the box itself
|
|
17540
|
+
* passes `height`, the box's height without that cap — a box measured at the
|
|
17541
|
+
* last cap would choose its side by the old room, not its own size.
|
|
17308
17542
|
*/
|
|
17309
|
-
function measureMenuPlacement(anchor, element, offset) {
|
|
17543
|
+
function measureMenuPlacement(anchor, element, offset, height = element.offsetHeight) {
|
|
17310
17544
|
const container = element.offsetParent ?? element.parentElement;
|
|
17311
17545
|
if (!container)
|
|
17312
17546
|
return null;
|
|
17313
17547
|
const containerRect = container.getBoundingClientRect();
|
|
17314
|
-
const
|
|
17548
|
+
const width = element.offsetWidth;
|
|
17315
17549
|
const { scrollLeft, scrollTop, scrollWidth, clientHeight } = container;
|
|
17316
17550
|
const left = Math.min(Math.max(anchor.left - containerRect.left + scrollLeft, 0), Math.max(scrollWidth - width, 0));
|
|
17317
|
-
//
|
|
17318
|
-
// the scroll container.
|
|
17319
|
-
|
|
17320
|
-
|
|
17321
|
-
|
|
17322
|
-
|
|
17323
|
-
|
|
17324
|
-
|
|
17325
|
-
|
|
17551
|
+
// The box's top edge below the line, its bottom edge above it, and the
|
|
17552
|
+
// visible part of the scroll container each leaves.
|
|
17553
|
+
const below = anchor.bottom - containerRect.top + scrollTop + offset;
|
|
17554
|
+
const above = anchor.top - containerRect.top + scrollTop - offset;
|
|
17555
|
+
const roomBelow = scrollTop + clientHeight - below;
|
|
17556
|
+
const roomAbove = above - scrollTop;
|
|
17557
|
+
if (height <= roomBelow)
|
|
17558
|
+
return { left, top: below, maxHeight: null };
|
|
17559
|
+
if (height <= roomAbove)
|
|
17560
|
+
return { left, top: above - height, maxHeight: null };
|
|
17561
|
+
// Fits neither: the side with more room, shrunk to it. A line out of
|
|
17562
|
+
// sight on both sides leaves no room to shrink to — below, as it is.
|
|
17563
|
+
if (roomAbove > roomBelow && roomAbove > 0)
|
|
17564
|
+
return { left, top: scrollTop, maxHeight: roomAbove };
|
|
17565
|
+
if (roomBelow > 0)
|
|
17566
|
+
return { left, top: below, maxHeight: roomBelow };
|
|
17567
|
+
return { left, top: below, maxHeight: null };
|
|
17326
17568
|
}
|
|
17327
17569
|
|
|
17328
17570
|
/** The dialect installed on an editor, as plugin state, so the send intent
|
|
@@ -18781,5 +19023,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
|
|
|
18781
19023
|
* Generated bundle index. Do not edit.
|
|
18782
19024
|
*/
|
|
18783
19025
|
|
|
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 };
|
|
19026
|
+
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, COLUMN_STARTING_LINES, 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_BLOCK_SPACING, 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, appendColumn, 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, removeLastColumn, 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 };
|
|
18785
19027
|
//# sourceMappingURL=h-k-dev-angular-email-editor.mjs.map
|