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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@h-k-dev/angular-email-editor",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "An email editor for Angular on ProseMirror — a visual composer and an HTML source editor over one schema that is the vocabulary of email HTML.",
5
5
  "license": "MIT",
6
6
  "author": "h-k-dev",
@@ -57,6 +57,12 @@ declare class AddressChipRemove {
57
57
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<AddressChipRemove, "ng-template[emailAddressChipRemove]", never, {}, {}, never, never, true, never>;
58
58
  }
59
59
 
60
+ /** The drag data type that carries a chip's address between address
61
+ inputs — one entry, in header form, exactly as the list holds it. It is
62
+ the only thing a chip's drag carries: no plain text, so no text field,
63
+ editor or page drop zone can take it — a chip lands in an address input
64
+ or nowhere. */
65
+ declare const ADDRESS_DRAG_TYPE = "application/x-email-address";
60
66
  /**
61
67
  * One address as a chip, the way Gmail draws it: the display name when the
62
68
  * mailbox has one, the address otherwise, and the whole header form in the
@@ -87,7 +93,20 @@ declare class AddressChipRemove {
87
93
  * to the clipboard, mouse or touch alike; a release or a drag before that
88
94
  * does not, and the browser's own context menu stays away. The chip shows
89
95
  * and says "Copied" for a moment (`data-copied`, a live `status` slot) and
90
- * emits `copied`.
96
+ * emits `copied`. A list that copies the chip itself — the address input
97
+ * on Ctrl+C or Cmd+C — shows the same through `showCopied()`.
98
+ *
99
+ * **Drag, when asked.** Marked `draggable`, the chip can be dragged — by a
100
+ * mouse or a pen; a touch keeps the press for the hold, so a phone's
101
+ * long-press never lifts the chip instead of copying it. The drag carries
102
+ * the header form as `ADDRESS_DRAG_TYPE` and nothing else — no text for
103
+ * another field to take — allows copy and move, and cancels a hold in progress: the browser starts a drag only
104
+ * once the press has moved, so the two gestures never both happen. A drag
105
+ * from the remove control is no drag. What travels under the pointer is
106
+ * the chip as a pill, whole — a copy with room around it, so no engine
107
+ * clips its edge or a ring it wears. `data-dragging` marks the chip while
108
+ * it is in flight. Where the drag lands, and whether the chip leaves its
109
+ * list, is the list's business — the address input does both.
91
110
  *
92
111
  * **It asks, it does not do.** The chip holds no list: `removed` is a
93
112
  * request the host answers by dropping the address. The address input
@@ -143,6 +162,18 @@ declare class AddressChip {
143
162
  /** The address was just copied: shown for a moment, and said. Reflected
144
163
  as `data-copied`. */
145
164
  protected readonly justCopied: _angular_core.WritableSignal<boolean>;
165
+ /** What the `status` slot says for a moment — a copy, or a list's
166
+ `announce()`. */
167
+ protected readonly status: _angular_core.WritableSignal<string>;
168
+ /** The chip may be dragged — to another address input, or as text into
169
+ any field. Off by default: a chip on its own has no list to leave; the
170
+ address input turns it on for an editable list. Reflected as
171
+ `draggable` for a mouse or pen, never for a touch. */
172
+ readonly draggable: _angular_core.InputSignalWithTransform<boolean, unknown>;
173
+ /** The last press was a touch: no drag, so the press stays the hold's. */
174
+ protected readonly touching: _angular_core.WritableSignal<boolean>;
175
+ /** The chip is being dragged. Reflected as `data-dragging`. */
176
+ protected readonly dragging: _angular_core.WritableSignal<boolean>;
146
177
  constructor();
147
178
  /** A press begins a hold — a primary pointer, mouse or touch alike, on
148
179
  the chip itself and not its remove control. */
@@ -151,18 +182,28 @@ declare class AddressChip {
151
182
  protected onPointermove(event: PointerEvent): void;
152
183
  /** Released, cancelled or gone before the time: no copy. */
153
184
  protected cancelHold(): void;
185
+ /** A drag begins: the address goes along in header form, as the
186
+ library's own type only, and a hold in progress is over.
187
+ Not from the remove control. */
188
+ protected onDragstart(event: DragEvent): void;
154
189
  /** The hold is the chip's, not the browser's: no context menu on it, on
155
190
  a phone or under a right button. */
156
191
  protected onContextmenu(event: Event): void;
157
- /** Writes the address to the clipboard: the async API first, and when
158
- it refuses — an unfocused document, a context without it — the old
159
- copy command on a selection made for the purpose. */
160
192
  /** Copies the address, in header form, to the clipboard — what a hold
161
193
  does, and what a host's own control may ask for — and shows and says
162
194
  so. The async API first; when it refuses (an unfocused document, a
163
195
  context without it), the old copy command on a selection made for the
164
196
  purpose. Resolves to whether the copy went. */
165
197
  copy(): Promise<boolean>;
198
+ /** Shows and says, for a moment, that the address is on the clipboard,
199
+ and emits `copied` — what a copy does once the clipboard has it. For a
200
+ list that put it there itself: the address input's Ctrl+C, which
201
+ writes the clipboard in the copy event, synchronously. */
202
+ showCopied(): void;
203
+ /** Says something about the chip through its `status` slot, for a
204
+ moment — what a copy says, and what a list says of a chip it just
205
+ received ("Moved to Cc: …"). */
206
+ announce(message: string): void;
166
207
  /** A remove template handed down by a list that renders the chip — the
167
208
  address input passes its own `emailAddressChipRemove` slot here. One
168
209
  in the chip's own content wins. */
@@ -186,8 +227,8 @@ declare class AddressChip {
186
227
  protected readonly note: _angular_core.Signal<string | null>;
187
228
  protected readonly title: _angular_core.Signal<string>;
188
229
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AddressChip, never>;
189
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AddressChip, "[email-address-chip]", never, { "address": { "alias": "address"; "required": true; "isSignal": true; }; "removable": { "alias": "removable"; "required": false; "isSignal": true; }; "inline": { "alias": "inline"; "required": false; "isSignal": true; }; "ariaCurrent": { "alias": "aria-current"; "required": false; "isSignal": true; }; "removeTabbable": { "alias": "removeTabbable"; "required": false; "isSignal": true; }; "removeLabel": { "alias": "removeLabel"; "required": false; "isSignal": true; }; "invalidLabel": { "alias": "invalidLabel"; "required": false; "isSignal": true; }; "pendingLabel": { "alias": "pendingLabel"; "required": false; "isSignal": true; }; "ariaDisabled": { "alias": "aria-disabled"; "required": false; "isSignal": true; }; "holdDelay": { "alias": "holdDelay"; "required": false; "isSignal": true; }; "copiedLabel": { "alias": "copiedLabel"; "required": false; "isSignal": true; }; "removeTemplate": { "alias": "removeTemplate"; "required": false; "isSignal": true; }; }, { "removed": "removed"; "copied": "copied"; }, ["removeSlot"], never, true, never>;
230
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AddressChip, "[email-address-chip]", never, { "address": { "alias": "address"; "required": true; "isSignal": true; }; "removable": { "alias": "removable"; "required": false; "isSignal": true; }; "inline": { "alias": "inline"; "required": false; "isSignal": true; }; "ariaCurrent": { "alias": "aria-current"; "required": false; "isSignal": true; }; "removeTabbable": { "alias": "removeTabbable"; "required": false; "isSignal": true; }; "removeLabel": { "alias": "removeLabel"; "required": false; "isSignal": true; }; "invalidLabel": { "alias": "invalidLabel"; "required": false; "isSignal": true; }; "pendingLabel": { "alias": "pendingLabel"; "required": false; "isSignal": true; }; "ariaDisabled": { "alias": "aria-disabled"; "required": false; "isSignal": true; }; "holdDelay": { "alias": "holdDelay"; "required": false; "isSignal": true; }; "copiedLabel": { "alias": "copiedLabel"; "required": false; "isSignal": true; }; "draggable": { "alias": "draggable"; "required": false; "isSignal": true; }; "removeTemplate": { "alias": "removeTemplate"; "required": false; "isSignal": true; }; }, { "removed": "removed"; "copied": "copied"; }, ["removeSlot"], never, true, never>;
190
231
  }
191
232
 
192
- export { AddressChip, AddressChipRemove };
233
+ export { ADDRESS_DRAG_TYPE, AddressChip, AddressChipRemove };
193
234
  export type { AddressChipRemoveContext };
@@ -26,6 +26,14 @@ declare class AddressInputLabel {
26
26
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<AddressInputLabel, "ng-template[emailAddressLabel]", never, {}, {}, never, never, true, never>;
27
27
  }
28
28
 
29
+ /** Where a drag over an input would land — the index in its list — and the
30
+ line drawn there, in the chip list's own coordinates. */
31
+ interface DropMarker {
32
+ index: number;
33
+ x: number;
34
+ y: number;
35
+ height: number;
36
+ }
29
37
  /**
30
38
  * An address field the way Gmail's works: committed addresses as chips,
31
39
  * free typing after them. Enter, comma, semicolon or a paste commits what
@@ -62,7 +70,9 @@ declare class AddressInputLabel {
62
70
  * the caret at the start of the typing, ← puts a highlight on the last chip
63
71
  * and walks back along the list; → walks forward, and past the last chip
64
72
  * returns to the caret. Enter or F2 — or a double click on
65
- * any chip — edits it,
73
+ * any chip — edits it, Alt+← and Alt+→ move it a place along the list,
74
+ * Ctrl+C (Cmd+C) copies it, as a hold does, and Ctrl+X cuts it — unless
75
+ * text is selected in the input, which copies as ever —
66
76
  * Backspace or Delete removes it, Escape drops the highlight, and so does
67
77
  * typing. A click on a chip highlights it. Reaching a chip either way is
68
78
  * being done with the typing: an address in the input becomes a chip first,
@@ -114,6 +124,32 @@ declare class AddressInputLabel {
114
124
  * the input, and the selection with it — focus leaving the control clears
115
125
  * the selection.
116
126
  *
127
+ * **Chips move between inputs by drag and drop.** A chip of an editable
128
+ * input can be dragged to another — To into Cc, as Gmail and Outlook do —
129
+ * and leaves its own list when the other takes it. The other commits it
130
+ * as it was, flagged or pending alike. A chip whose address the other
131
+ * already holds is absorbed, as Gmail does: it leaves its list and the
132
+ * other keeps its own entry. A full list (From holds one) refuses the
133
+ * drop, and the chip stays. Dropped in its own list, a chip is reordered:
134
+ * it moves to the line; the line is not drawn where the chip already is. Alt (Option), or Ctrl, makes
135
+ * it a copy — onto a duplicate, a copy is nothing, so refused. Nothing
136
+ * moves while a drag is over a target: a thin line between its chips
137
+ * (`drop-marker`) shows where the chip will land, before or after the chip
138
+ * under the pointer, and the drop puts it there; the host carries
139
+ * `data-dropping` meanwhile. Only chips are places: a draft — typed in the
140
+ * input, or left at the end of the list when the row lost focus — is not,
141
+ * and a drop lands before it.
142
+ * A drop counts as working both fields: each is touched.
143
+ * A chip lands in an address input or nowhere: it carries no plain text,
144
+ * so a subject line or an editor can't take it. `emailAddressDragGroup` on
145
+ * the element around a writer's rows keeps its chips among them. Plain text
146
+ * dropped from elsewhere is a paste — the addresses become chips, the rest
147
+ * is left typed.
148
+ * `moveTo()` is the same move for the keyboard — a host's "Move to Cc" —
149
+ * and the moved chip says so (`movedLabel`). A touch is never a drag: on
150
+ * a phone the press is the chip's hold-to-copy. `allowDrag` turns it off;
151
+ * a disabled or read-only input is neither source nor target.
152
+ *
117
153
  * **The chips' remove control is a template slot.** An
118
154
  * `ng-template[emailAddressChipRemove]` in the input's content is handed to
119
155
  * every chip it renders, in place of the default × button.
@@ -155,6 +191,13 @@ declare class AddressInput implements FormValueControl<string[]> {
155
191
  readonly invalidLabel: _angular_core.InputSignal<string>;
156
192
  /** The chips' note on a placeholder a template fills in later. */
157
193
  readonly pendingLabel: _angular_core.InputSignal<string>;
194
+ /** What a chip moved into this input says, before its address — a host
195
+ with labelled rows says where: "Moved to Cc:". */
196
+ readonly movedLabel: _angular_core.InputSignal<string>;
197
+ /** Chips may be dragged out of this input and dropped into it. Set false
198
+ for a row that only shows; a disabled or read-only input never takes
199
+ part either way. */
200
+ readonly allowDrag: _angular_core.InputSignalWithTransform<boolean, unknown>;
158
201
  /** The input's `name` attribute; the directive derives one from the path. */
159
202
  readonly name: _angular_core.InputSignal<string>;
160
203
  readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
@@ -177,6 +220,8 @@ declare class AddressInput implements FormValueControl<string[]> {
177
220
  /** The host's remove template, passed on to every chip. */
178
221
  protected readonly removeSlot: _angular_core.Signal<AddressChipRemove | undefined>;
179
222
  protected readonly field: _angular_core.Signal<ElementRef<HTMLInputElement>>;
223
+ /** The list of chips, where a press on a draggable chip parks focus. */
224
+ protected readonly chipList: _angular_core.Signal<ElementRef<HTMLElement>>;
180
225
  /** Focus is somewhere in the control — the input or a chip's remove
181
226
  button. The chips are chips only then. Read-only; for a host's own
182
227
  frame (a form field whose label floats on it). */
@@ -209,6 +254,15 @@ declare class AddressInput implements FormValueControl<string[]> {
209
254
  /** Nothing may change: disabled or read-only. Chips lose their remove
210
255
  button, the input is out of play. */
211
256
  protected readonly locked: _angular_core.Signal<boolean>;
257
+ /** Chips can be dragged out of the list, and dropped into it. */
258
+ protected readonly canDrag: _angular_core.Signal<boolean>;
259
+ /** Where a drag over the input would land: the index in the list, and
260
+ the line drawn there — in the chip list's own coordinates. Null while
261
+ no drag the input would take is over it. Drawn on top, out of the
262
+ flow, so nothing moves under the pointer. */
263
+ protected readonly dropMarker: _angular_core.WritableSignal<DropMarker | null>;
264
+ /** A drag the input would take is over it. */
265
+ protected readonly dropping: _angular_core.Signal<boolean>;
212
266
  /** Invalid *and* touched — the moment the state becomes the user's business. */
213
267
  protected readonly flagged: _angular_core.Signal<boolean>;
214
268
  /** Splits a run into addresses and adds the new ones to the end of the
@@ -246,7 +300,12 @@ declare class AddressInput implements FormValueControl<string[]> {
246
300
  its button, the gap between — leaves the caret where it is. The
247
301
  browser would otherwise move focus to the body for the press and back
248
302
  on the click, and in that instant the row would drop to text and
249
- reflow: a flash, and a blur that commits and touches for nothing. */
303
+ reflow: a flash, and a blur that commits and touches for nothing.
304
+ Except a mouse's press on a draggable chip: no engine starts a drag
305
+ from a press whose default was declined, so it keeps it, and the
306
+ press's focus lands on the chip list instead (`tabindex="-1"`) —
307
+ still inside the control, so nothing commits; the click or the drag's
308
+ end brings the caret back. */
250
309
  protected keepCaret(event: MouseEvent): void;
251
310
  /** A click on a chip — not on its remove control — picks it, and only
252
311
  that: a click on the picked chip picks it again. The caret is in the
@@ -259,13 +318,51 @@ declare class AddressInput implements FormValueControl<string[]> {
259
318
  clipboard, as a hold on the chip does; the chip shows and says so.
260
319
  Resolves to whether the copy went. */
261
320
  copy(address?: string | null): Promise<boolean>;
321
+ /** Moves a chip — the picked one by default — to another address input:
322
+ the keyboard's way to do what a drag does, for a host's own "Move to
323
+ Cc". The target takes it as it is, to the end of its list — before
324
+ a draft the row was left with — and it
325
+ leaves this one; both are touched, and the moved chip says so
326
+ (`movedLabel`). One the target already holds is absorbed: it leaves
327
+ here, and the target keeps its own entry. A full target, or either
328
+ input locked, moves nothing. Returns whether it moved. */
329
+ moveTo(target: AddressInput, address?: string | null): boolean;
330
+ /** A chip of this list started a drag: remember it, so a target on the
331
+ page can judge the drop before it happens and tell this list to let
332
+ go after. */
333
+ protected onChipDragstart(address: string): void;
334
+ /** The drag ended: if an address input took the chip as a move, it
335
+ leaves — through `remove()`, as the × takes it — and the field is
336
+ touched. The press parked focus on the list; the caret comes back. */
337
+ protected onChipDragend(): void;
338
+ protected onDragover(event: DragEvent): void;
339
+ /** Leaving for somewhere outside the control: the drag is no longer over
340
+ it. (A leave with nowhere named — some engines — ends it too; the
341
+ next `dragover` inside brings it back.) */
342
+ protected onDragleave(event: DragEvent): void;
343
+ /** The drop: a chip is committed as it was; plain text from elsewhere is
344
+ a paste — its addresses become chips, the rest joins the typing. What
345
+ was typed stays. A chip the list holds already is absorbed by a move:
346
+ nothing is added, and the source lets it go. Nothing added otherwise
347
+ (the limit) is no drop: the source keeps its chip. */
348
+ protected onDrop(event: DragEvent): void;
262
349
  protected onFocusin(): void;
263
350
  protected onInput(input: HTMLInputElement): void;
264
351
  protected onKeydown(event: KeyboardEvent, input: HTMLInputElement): void;
265
352
  /** A paste of several addresses: the addresses become chips, the rest
266
353
  joins what the input already holds. A single token is left to the
267
- input, so a name with spaces can still be edited before it commits. */
354
+ input, so a name with spaces can still be edited before it commits —
355
+ but a chip's own copy (Ctrl+C, Ctrl+X, a hold) comes back as a chip,
356
+ as it was. With a chip picked, what is pasted goes right after it. */
268
357
  protected onPaste(event: ClipboardEvent, input: HTMLInputElement): void;
358
+ /** Ctrl+C or Ctrl+X (Cmd on a Mac, or the Edit menu) with a chip picked
359
+ and no text selected: the chip goes on the clipboard — its header
360
+ form, as text and as the library's own type, so a paste into an
361
+ address input brings it back as a chip — and shows and says so, as a
362
+ hold does. A cut then removes it, as the × would. */
363
+ protected onClipboard(event: ClipboardEvent, input: HTMLInputElement, cut: boolean): void;
364
+ /** A chip's hold copied it: remembered, so a paste of it is a chip. */
365
+ protected onChipCopied(address: string): void;
269
366
  /** Focus arrived in the input: the typos at the end of the list come back
270
367
  into it, to be fixed — unless the user is already typing there. They
271
368
  come back as plain typing, not flagged: the caret is on them, and the
@@ -278,7 +375,7 @@ declare class AddressInput implements FormValueControl<string[]> {
278
375
  protected onBlur(event: FocusEvent, input: HTMLInputElement): void;
279
376
  protected onFocusout(event: FocusEvent): void;
280
377
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AddressInput, never>;
281
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AddressInput, "[email-address-input]", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "ariaLabelledby": { "alias": "aria-labelledby"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "ariaDescribedby": { "alias": "aria-describedby"; "required": false; "isSignal": true; }; "limit": { "alias": "limit"; "required": false; "isSignal": true; }; "removeLabel": { "alias": "removeLabel"; "required": false; "isSignal": true; }; "invalidLabel": { "alias": "invalidLabel"; "required": false; "isSignal": true; }; "pendingLabel": { "alias": "pendingLabel"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touch": "touch"; }, ["labelSlot", "removeSlot"], never, true, never>;
378
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AddressInput, "[email-address-input]", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "ariaLabelledby": { "alias": "aria-labelledby"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "ariaDescribedby": { "alias": "aria-describedby"; "required": false; "isSignal": true; }; "limit": { "alias": "limit"; "required": false; "isSignal": true; }; "removeLabel": { "alias": "removeLabel"; "required": false; "isSignal": true; }; "invalidLabel": { "alias": "invalidLabel"; "required": false; "isSignal": true; }; "pendingLabel": { "alias": "pendingLabel"; "required": false; "isSignal": true; }; "movedLabel": { "alias": "movedLabel"; "required": false; "isSignal": true; }; "allowDrag": { "alias": "allowDrag"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touch": "touch"; }, ["labelSlot", "removeSlot"], never, true, never>;
282
379
  }
283
380
 
284
381
  /** The error kinds `addressList` reports, for a host that switches on them. */
@@ -324,5 +421,29 @@ interface AddressListOptions {
324
421
  */
325
422
  declare function addressList<TPathKind extends PathKind = PathKind.Root>(path: SchemaPath<string[], SchemaPathRules.Supported, TPathKind>, options?: AddressListOptions): void;
326
423
 
327
- export { ADDRESS_LIST_EMPTY, ADDRESS_LIST_INVALID, ADDRESS_LIST_TOO_MANY, AddressInput, AddressInputLabel, addressList };
424
+ /**
425
+ * Scopes chip drag and drop to the address inputs inside it: they trade
426
+ * chips with each other and refuse anyone else's — a writer's From, To, Cc
427
+ * and Bcc, and not the rows of another writer on the same page. Put it on
428
+ * whatever holds the rows:
429
+ *
430
+ * <form emailAddressDragGroup [formRoot]="envelope">
431
+ * <div email-address-input [formField]="envelope.from" limit="1"></div>
432
+ * <div email-address-input [formField]="envelope.to"></div>
433
+ * …
434
+ * </form>
435
+ *
436
+ * The nearest group around an input is its group. Inputs in no group make
437
+ * up one group of their own, so a page with a single writer needs none.
438
+ * Behaviour only: it renders nothing and sets no attribute.
439
+ *
440
+ * A chip lands in an address input or nowhere — it carries no plain text,
441
+ * so a subject line, an editor or any other field leaves it alone.
442
+ */
443
+ declare class AddressDragGroup {
444
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<AddressDragGroup, never>;
445
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<AddressDragGroup, "[emailAddressDragGroup]", ["emailAddressDragGroup"], {}, {}, never, never, true, never>;
446
+ }
447
+
448
+ export { ADDRESS_LIST_EMPTY, ADDRESS_LIST_INVALID, ADDRESS_LIST_TOO_MANY, AddressDragGroup, AddressInput, AddressInputLabel, addressList };
328
449
  export type { AddressListOptions };
@@ -24,6 +24,12 @@ declare const KEEP_FOCUS_EXCEPT = "input, textarea, select, [contenteditable]:no
24
24
  *
25
25
  * It needs no editor: what keeps focus is whichever element has it, so the
26
26
  * same directive serves a composer's address rows.
27
+ *
28
+ * A press on something marked `draggable="true"` — an address chip that
29
+ * can be dragged to another row — is always left alone, exceptions or not:
30
+ * no engine starts a drag from a press whose default was declined. Such an
31
+ * element keeps focus in its own way (the address input parks it on its
32
+ * chip list).
27
33
  */
28
34
  declare class KeepFocus {
29
35
  #private;
@@ -2042,6 +2042,8 @@ declare const Image: _h_k_dev_angular_email_editor.NodeExtension;
2042
2042
  not text, so it is exempt from the dual-contrast rule. */
2043
2043
  declare const Divider: _h_k_dev_angular_email_editor.NodeExtension;
2044
2044
 
2045
+ /** The default button's fill — the primary blue — and the text on it. */
2046
+ declare const BUTTON_FILL = "rgb(26, 115, 232)";
2045
2047
  /** The button's canonical styling — the *border-based* bulletproof button:
2046
2048
  the touch target (≥ 44px tall, per the ledger) comes from borders in the
2047
2049
  background colour, not from padding, because Outlook's Word engine ignores
@@ -2054,8 +2056,6 @@ declare const Divider: _h_k_dev_angular_email_editor.NodeExtension;
2054
2056
  rgb to stay stable. The label's weight and slant are the button's
2055
2057
  own (`bold`, `italic`): this is a default button's. */
2056
2058
  declare const BUTTON_STYLE: string;
2057
- /** The default button's fill — the primary blue — and the text on it. */
2058
- declare const BUTTON_FILL = "rgb(26, 115, 232)";
2059
2059
  /** The canonical style of a button with that label styling and fill: bold
2060
2060
  is `font-weight: bold` and not bold `normal` (said, never left out — a
2061
2061
  client's own anchor styling may be bold); italic adds `font-style`