@h-k-dev/angular-email-editor 0.0.5 → 0.0.7

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.
@@ -30,7 +30,7 @@ function editorState(editor, options = {}) {
30
30
  *
31
31
  * readonly actions = injectActions(() => this.editor());
32
32
  *
33
- * <button [emailAction]="actions.get('bold')">…</button>
33
+ * <button emailAction="bold" [emailActionFrom]="actions">…</button>
34
34
  *
35
35
  * `editor` is read reactively: when it changes — a composer switching to its
36
36
  * code view — the actions are the new editor's. Its kit decides what exists:
@@ -78,7 +78,9 @@ function injectActions(editor, options = {}) {
78
78
  return byId;
79
79
  const hosted = new Map((options.host ?? []).map((over) => [over.id, over]));
80
80
  for (const action of current.actions) {
81
- const given = options.override?.[action.id];
81
+ // Its own entry only: an id such as `constructor` overrides nothing.
82
+ const { override } = options;
83
+ const given = override && Object.hasOwn(override, action.id) ? override[action.id] : undefined;
82
84
  // A host action under a kit's id is an override by another name.
83
85
  const over = given ? { id: action.id, ...given } : hosted.get(action.id);
84
86
  hosted.delete(action.id);
@@ -102,11 +104,15 @@ function injectActions(editor, options = {}) {
102
104
  * Makes the host's own control the trigger of an editor action: a click runs
103
105
  * it, and the control says what the action's state is.
104
106
  *
105
- * <button mat-icon-button [emailAction]="actions.get('bold')" #bold="emailAction"
106
- * [disabled]="bold.disabled()">
107
+ * <button mat-icon-button emailAction="bold" [emailActionFrom]="actions"
108
+ * #bold="emailAction" [disabled]="bold.disabled()">
107
109
  * <mat-icon>format_bold</mat-icon>
108
110
  * </button>
109
111
  *
112
+ * The action is named by its id, and looked up in the list it is from
113
+ * (`injectActions`) here, in a `computed`: a template binds values and reads
114
+ * signals, it calls no lookup of its own.
115
+ *
110
116
  * Behaviour only, and ARIA only where the host's widget has not spoken:
111
117
  * - `aria-pressed` for a toggle, and `aria-disabled` when it cannot run —
112
118
  * both off with `[emailActionAria]="false"` for a widget that writes its own
@@ -123,9 +129,14 @@ function injectActions(editor, options = {}) {
123
129
  * dialog, a picker) never has focus taken from what it opened.
124
130
  */
125
131
  class ActionTrigger {
126
- /** The action to trigger — `actions.get(id)`. `undefined` (no editor yet,
127
- or a kit without it) is a trigger with nothing to do: disabled. */
128
- action = input.required({ ...(ngDevMode ? { debugName: "action" } : /* istanbul ignore next */ {}), alias: 'emailAction' });
132
+ /** The id of the action to trigger. */
133
+ id = input.required({ ...(ngDevMode ? { debugName: "id" } : /* istanbul ignore next */ {}), alias: 'emailAction' });
134
+ /** The actions it is one of — what `injectActions` returned. */
135
+ from = input.required({ ...(ngDevMode ? { debugName: "from" } : /* istanbul ignore next */ {}), alias: 'emailActionFrom' });
136
+ /** The action itself. `undefined` (no editor yet, or a kit without it) is a
137
+ trigger with nothing to do: disabled. */
138
+ action = computed(() => this.from().get(this.id()), /* @ts-ignore */
139
+ ...(ngDevMode ? [{ debugName: "action" }] : /* istanbul ignore next */ []));
129
140
  /** Whether this directive writes `aria-pressed` and `aria-disabled`. */
130
141
  aria = input(true, { ...(ngDevMode ? { debugName: "aria" } : /* istanbul ignore next */ {}), alias: 'emailActionAria', transform: booleanAttribute });
131
142
  /** Whether the caret returns to the editor after the action ran. */
@@ -152,7 +163,7 @@ class ActionTrigger {
152
163
  return applied;
153
164
  }
154
165
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ActionTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive });
155
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.6", type: ActionTrigger, isStandalone: true, selector: "[emailAction]", inputs: { action: { classPropertyName: "action", publicName: "emailAction", isSignal: true, isRequired: true, transformFunction: null }, aria: { classPropertyName: "aria", publicName: "emailActionAria", isSignal: true, isRequired: false, transformFunction: null }, returnFocus: { classPropertyName: "returnFocus", publicName: "emailActionFocus", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "click": "run()" }, properties: { "attr.aria-pressed": "ariaPressed()", "attr.aria-disabled": "ariaDisabled()" } }, exportAs: ["emailAction"], ngImport: i0 });
166
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.6", type: ActionTrigger, isStandalone: true, selector: "[emailAction]", inputs: { id: { classPropertyName: "id", publicName: "emailAction", isSignal: true, isRequired: true, transformFunction: null }, from: { classPropertyName: "from", publicName: "emailActionFrom", isSignal: true, isRequired: true, transformFunction: null }, aria: { classPropertyName: "aria", publicName: "emailActionAria", isSignal: true, isRequired: false, transformFunction: null }, returnFocus: { classPropertyName: "returnFocus", publicName: "emailActionFocus", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "click": "run()" }, properties: { "attr.aria-pressed": "ariaPressed()", "attr.aria-disabled": "ariaDisabled()" } }, exportAs: ["emailAction"], ngImport: i0 });
156
167
  }
157
168
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ActionTrigger, decorators: [{
158
169
  type: Directive,
@@ -165,7 +176,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
165
176
  '(click)': 'run()',
166
177
  },
167
178
  }]
168
- }], propDecorators: { action: [{ type: i0.Input, args: [{ isSignal: true, alias: "emailAction", required: true }] }], aria: [{ type: i0.Input, args: [{ isSignal: true, alias: "emailActionAria", required: false }] }], returnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "emailActionFocus", required: false }] }] } });
179
+ }], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "emailAction", required: true }] }], from: [{ type: i0.Input, args: [{ isSignal: true, alias: "emailActionFrom", required: true }] }], aria: [{ type: i0.Input, args: [{ isSignal: true, alias: "emailActionAria", required: false }] }], returnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "emailActionFocus", required: false }] }] } });
169
180
 
170
181
  /*
171
182
  * Public API Surface of @h-k-dev/angular-email-editor/actions
@@ -1 +1 @@
1
- {"version":3,"file":"h-k-dev-angular-email-editor-actions.mjs","sources":["../../../projects/angular-email-editor/actions/actions.ts","../../../projects/angular-email-editor/actions/action-trigger.ts","../../../projects/angular-email-editor/actions/public-api.ts","../../../projects/angular-email-editor/actions/h-k-dev-angular-email-editor-actions.ts"],"sourcesContent":["import { Injector, Signal, computed, effect, inject, signal, untracked } from '@angular/core';\nimport { EditorState } from 'prosemirror-state';\nimport { Editor, EditorAction, isActionEnabled } from '@h-k-dev/angular-email-editor';\n\n/**\n * An editor's state as a signal: the text, the selection, the stored marks —\n * whatever changed, the signal has the new one. It follows the editor it is\n * given, so handing it \"the source pane in code view, the email editor\n * otherwise\" is one `computed`; `undefined` while there is none.\n *\n * It listens through `editor.subscribe`, so the editor can already exist:\n * nothing has to be in the kit before the editor is made.\n *\n * Call in an injection context, or hand it an injector.\n */\nexport function editorState(\n editor: () => Editor | undefined,\n options: { injector?: Injector } = {},\n): Signal<EditorState | undefined> {\n const state = signal<EditorState | undefined>(undefined);\n effect(\n (onCleanup) => {\n const current = editor();\n state.set(current?.state);\n if (current) onCleanup(current.subscribe(() => state.set(current.state)));\n },\n { injector: options.injector },\n );\n return state.asReadonly();\n}\n\n/**\n * An action of the host's own: something that opens its UI — a link dialog,\n * a colour or table picker — rather than running a command. It has a `run`,\n * not a `command`, on purpose: a command is *asked* whether it would apply\n * (called without a dispatch), and a function that opens a dialog must never\n * be called to ask.\n *\n * Two ways in, by what it is:\n * - `host` — an action of its own, there for every editor: \"Link\", which\n * no extension can offer because it needs the host's dialog;\n * - `override` — the host's `run` *over* an action the kit declares, by its\n * id: a toolbar's \"Insert table\" that opens a size picker instead of\n * inserting one. It exists only where the kit's action does (so not in a\n * code view), and what it leaves out — when it is on, whether it can run —\n * is still the extension's answer.\n */\nexport interface HostAction {\n id: string;\n /** What triggering it does. Focus is the host's from here on: the caret\n is not sent back to the editor after it. */\n run: () => void;\n /** On at the selection — makes it a toggle. */\n isActive?: (state: EditorState) => boolean;\n /** Can run right now. Absent: the extension action's answer when it\n stands over one, else yes. */\n isEnabled?: (state: EditorState) => boolean;\n}\n\n/** An action bound to a live editor: what a button needs. */\nexport interface BoundAction {\n /** The action as its extension declared it — id, title, icon, keywords;\n `undefined` for a {@link HostAction} that stands alone. */\n readonly action: EditorAction | undefined;\n readonly id: string;\n /** It is the host's `run`: what happens after — where focus goes — is the\n host's too. */\n readonly external: boolean;\n /** On at the selection. Always false for an action with no \"on\". */\n readonly pressed: Signal<boolean>;\n /** Whether it is a toggle at all — whether `pressed` means anything. */\n readonly toggles: boolean;\n /** Cannot run right now. */\n readonly disabled: Signal<boolean>;\n /** Runs it on the editor; false when it did not apply. */\n run(): boolean;\n /** Puts the caret back in the editor it acts on. */\n focus(): void;\n}\n\n/** The actions of the editor being watched. */\nexport interface EditorActions {\n /** The action of that id — `undefined` while there is no editor, and when\n the editor's kit has no such action: a button for it has nothing to do.\n Reactive: it follows the editor. */\n get(id: string): BoundAction | undefined;\n /** Every action of the current editor, in kit order. */\n readonly all: Signal<readonly BoundAction[]>;\n /** The watched editor's state. */\n readonly state: Signal<EditorState | undefined>;\n}\n\n/**\n * The actions of an editor, bound and live — for a toolbar, a bubble menu,\n * a menu:\n *\n * readonly actions = injectActions(() => this.editor());\n *\n * <button [emailAction]=\"actions.get('bold')\">…</button>\n *\n * `editor` is read reactively: when it changes — a composer switching to its\n * code view — the actions are the new editor's. Its kit decides what exists:\n * the source pane offers the marks, so there a list button has no action\n * and shows disabled, with no routing written anywhere.\n *\n * `host` and `override` bring in the host's own — see {@link HostAction} — so\n * that one list serves a surface whose buttons are not all the editor's.\n *\n * Call in an injection context, or hand it an injector.\n */\nexport function injectActions(\n editor: () => Editor | undefined,\n options: {\n host?: readonly HostAction[];\n override?: Readonly<Record<string, Omit<HostAction, 'id'>>>;\n injector?: Injector;\n } = {},\n): EditorActions {\n const injector = options.injector ?? inject(Injector);\n const state = editorState(editor, { injector });\n\n const bind = (current: Editor, action?: EditorAction, over?: HostAction): BoundAction => {\n const isActive = over?.isActive ?? action?.isActive;\n const isEnabled = (now: EditorState) =>\n over?.isEnabled ? over.isEnabled(now) : action ? isActionEnabled(action, now) : true;\n return {\n action,\n id: (over ?? action)!.id,\n external: !!over,\n toggles: !!isActive,\n pressed: computed(() => {\n const now = state();\n return !!now && !!isActive?.(now);\n }),\n disabled: computed(() => {\n const now = state();\n return !now || !isEnabled(now);\n }),\n run: () => {\n if (!over) return current.exec(action!.command);\n over.run();\n return true;\n },\n focus: () => current.focus(),\n };\n };\n\n const bound = computed(() => {\n const current = editor();\n const byId = new Map<string, BoundAction>();\n // Binding reads no state: only the editor decides which actions exist.\n if (!current) return byId;\n const hosted = new Map((options.host ?? []).map((over) => [over.id, over]));\n for (const action of current.actions) {\n const given = options.override?.[action.id];\n // A host action under a kit's id is an override by another name.\n const over = given ? { id: action.id, ...given } : hosted.get(action.id);\n hosted.delete(action.id);\n byId.set(\n action.id,\n untracked(() => bind(current, action, over)),\n );\n }\n // What stands alone comes after the kit's own, in the order given.\n for (const over of hosted.values()) {\n byId.set(\n over.id,\n untracked(() => bind(current, undefined, over)),\n );\n }\n return byId;\n });\n\n return {\n get: (id) => bound().get(id),\n all: computed(() => [...bound().values()]),\n state,\n };\n}\n","import { Directive, booleanAttribute, computed, input } from '@angular/core';\nimport { BoundAction } from './actions';\n\n/**\n * Makes the host's own control the trigger of an editor action: a click runs\n * it, and the control says what the action's state is.\n *\n * <button mat-icon-button [emailAction]=\"actions.get('bold')\" #bold=\"emailAction\"\n * [disabled]=\"bold.disabled()\">\n * <mat-icon>format_bold</mat-icon>\n * </button>\n *\n * Behaviour only, and ARIA only where the host's widget has not spoken:\n * - `aria-pressed` for a toggle, and `aria-disabled` when it cannot run —\n * both off with `[emailActionAria]=\"false\"` for a widget that writes its own\n * (a Material button toggle);\n * - never the native `disabled`, a class or a style: how disabled *looks* is\n * the host's, bound from `disabled()` as above. A control that is only\n * `aria-disabled` stays reachable by keyboard, which is what a toolbar wants;\n * - a click on a disabled trigger runs nothing.\n *\n * After running, the caret goes back to the editor the action ran on — a\n * no-op for a pointer press under `emailKeepFocus`, the way back for a key\n * press in a toolbar. `[emailActionFocus]=\"false\"` leaves focus on the\n * control, as the ARIA toolbar pattern has it. A host's own action (a link\n * dialog, a picker) never has focus taken from what it opened.\n */\n@Directive({\n selector: '[emailAction]',\n exportAs: 'emailAction',\n host: {\n '[attr.aria-pressed]': 'ariaPressed()',\n '[attr.aria-disabled]': 'ariaDisabled()',\n '(click)': 'run()',\n },\n})\nexport class ActionTrigger {\n /** The action to trigger — `actions.get(id)`. `undefined` (no editor yet,\n or a kit without it) is a trigger with nothing to do: disabled. */\n readonly action = input.required<BoundAction | undefined>({ alias: 'emailAction' });\n\n /** Whether this directive writes `aria-pressed` and `aria-disabled`. */\n readonly aria = input(true, { alias: 'emailActionAria', transform: booleanAttribute });\n\n /** Whether the caret returns to the editor after the action ran. */\n readonly returnFocus = input(true, { alias: 'emailActionFocus', transform: booleanAttribute });\n\n /** On at the selection. */\n readonly pressed = computed(() => this.action()?.pressed() ?? false);\n\n /** Cannot run right now — or has no action at all. */\n readonly disabled = computed(() => this.action()?.disabled() ?? true);\n\n protected readonly ariaPressed = computed(() =>\n this.aria() && this.action()?.toggles ? this.pressed() : null,\n );\n\n protected readonly ariaDisabled = computed(() => (this.aria() && this.disabled() ? true : null));\n\n /** Runs the action, as a click does. False when it did not apply. */\n run(): boolean {\n const action = this.action();\n if (!action || this.disabled()) return false;\n const applied = action.run();\n // A host's own action opened something of the host's: focus is its now.\n if (this.returnFocus() && !action.external) action.focus();\n return applied;\n }\n}\n","/*\n * Public API Surface of @h-k-dev/angular-email-editor/actions\n */\n\nexport * from './actions';\nexport * from './action-trigger';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"h-k-dev-angular-email-editor-actions.mjs","sources":["../../../projects/angular-email-editor/actions/actions.ts","../../../projects/angular-email-editor/actions/action-trigger.ts","../../../projects/angular-email-editor/actions/public-api.ts","../../../projects/angular-email-editor/actions/h-k-dev-angular-email-editor-actions.ts"],"sourcesContent":["import { Injector, Signal, computed, effect, inject, signal, untracked } from '@angular/core';\nimport { EditorState } from 'prosemirror-state';\nimport { Editor, EditorAction, isActionEnabled } from '@h-k-dev/angular-email-editor';\n\n/**\n * An editor's state as a signal: the text, the selection, the stored marks —\n * whatever changed, the signal has the new one. It follows the editor it is\n * given, so handing it \"the source pane in code view, the email editor\n * otherwise\" is one `computed`; `undefined` while there is none.\n *\n * It listens through `editor.subscribe`, so the editor can already exist:\n * nothing has to be in the kit before the editor is made.\n *\n * Call in an injection context, or hand it an injector.\n */\nexport function editorState(\n editor: () => Editor | undefined,\n options: { injector?: Injector } = {},\n): Signal<EditorState | undefined> {\n const state = signal<EditorState | undefined>(undefined);\n effect(\n (onCleanup) => {\n const current = editor();\n state.set(current?.state);\n if (current) onCleanup(current.subscribe(() => state.set(current.state)));\n },\n { injector: options.injector },\n );\n return state.asReadonly();\n}\n\n/**\n * An action of the host's own: something that opens its UI — a link dialog,\n * a colour or table picker — rather than running a command. It has a `run`,\n * not a `command`, on purpose: a command is *asked* whether it would apply\n * (called without a dispatch), and a function that opens a dialog must never\n * be called to ask.\n *\n * Two ways in, by what it is:\n * - `host` — an action of its own, there for every editor: \"Link\", which\n * no extension can offer because it needs the host's dialog;\n * - `override` — the host's `run` *over* an action the kit declares, by its\n * id: a toolbar's \"Insert table\" that opens a size picker instead of\n * inserting one. It exists only where the kit's action does (so not in a\n * code view), and what it leaves out — when it is on, whether it can run —\n * is still the extension's answer.\n */\nexport interface HostAction {\n id: string;\n /** What triggering it does. Focus is the host's from here on: the caret\n is not sent back to the editor after it. */\n run: () => void;\n /** On at the selection — makes it a toggle. */\n isActive?: (state: EditorState) => boolean;\n /** Can run right now. Absent: the extension action's answer when it\n stands over one, else yes. */\n isEnabled?: (state: EditorState) => boolean;\n}\n\n/** An action bound to a live editor: what a button needs. */\nexport interface BoundAction {\n /** The action as its extension declared it — id, title, icon, keywords;\n `undefined` for a {@link HostAction} that stands alone. */\n readonly action: EditorAction | undefined;\n readonly id: string;\n /** It is the host's `run`: what happens after — where focus goes — is the\n host's too. */\n readonly external: boolean;\n /** On at the selection. Always false for an action with no \"on\". */\n readonly pressed: Signal<boolean>;\n /** Whether it is a toggle at all — whether `pressed` means anything. */\n readonly toggles: boolean;\n /** Cannot run right now. */\n readonly disabled: Signal<boolean>;\n /** Runs it on the editor; false when it did not apply. */\n run(): boolean;\n /** Puts the caret back in the editor it acts on. */\n focus(): void;\n}\n\n/** The actions of the editor being watched. */\nexport interface EditorActions {\n /** The action of that id — `undefined` while there is no editor, and when\n the editor's kit has no such action: a button for it has nothing to do.\n Reactive: it follows the editor. */\n get(id: string): BoundAction | undefined;\n /** Every action of the current editor, in kit order. */\n readonly all: Signal<readonly BoundAction[]>;\n /** The watched editor's state. */\n readonly state: Signal<EditorState | undefined>;\n}\n\n/**\n * The actions of an editor, bound and live — for a toolbar, a bubble menu,\n * a menu:\n *\n * readonly actions = injectActions(() => this.editor());\n *\n * <button emailAction=\"bold\" [emailActionFrom]=\"actions\">…</button>\n *\n * `editor` is read reactively: when it changes — a composer switching to its\n * code view — the actions are the new editor's. Its kit decides what exists:\n * the source pane offers the marks, so there a list button has no action\n * and shows disabled, with no routing written anywhere.\n *\n * `host` and `override` bring in the host's own — see {@link HostAction} — so\n * that one list serves a surface whose buttons are not all the editor's.\n *\n * Call in an injection context, or hand it an injector.\n */\nexport function injectActions(\n editor: () => Editor | undefined,\n options: {\n host?: readonly HostAction[];\n override?: Readonly<Record<string, Omit<HostAction, 'id'>>>;\n injector?: Injector;\n } = {},\n): EditorActions {\n const injector = options.injector ?? inject(Injector);\n const state = editorState(editor, { injector });\n\n const bind = (current: Editor, action?: EditorAction, over?: HostAction): BoundAction => {\n const isActive = over?.isActive ?? action?.isActive;\n const isEnabled = (now: EditorState) =>\n over?.isEnabled ? over.isEnabled(now) : action ? isActionEnabled(action, now) : true;\n return {\n action,\n id: (over ?? action)!.id,\n external: !!over,\n toggles: !!isActive,\n pressed: computed(() => {\n const now = state();\n return !!now && !!isActive?.(now);\n }),\n disabled: computed(() => {\n const now = state();\n return !now || !isEnabled(now);\n }),\n run: () => {\n if (!over) return current.exec(action!.command);\n over.run();\n return true;\n },\n focus: () => current.focus(),\n };\n };\n\n const bound = computed(() => {\n const current = editor();\n const byId = new Map<string, BoundAction>();\n // Binding reads no state: only the editor decides which actions exist.\n if (!current) return byId;\n const hosted = new Map((options.host ?? []).map((over) => [over.id, over]));\n for (const action of current.actions) {\n // Its own entry only: an id such as `constructor` overrides nothing.\n const { override } = options;\n const given = override && Object.hasOwn(override, action.id) ? override[action.id] : undefined;\n // A host action under a kit's id is an override by another name.\n const over = given ? { id: action.id, ...given } : hosted.get(action.id);\n hosted.delete(action.id);\n byId.set(\n action.id,\n untracked(() => bind(current, action, over)),\n );\n }\n // What stands alone comes after the kit's own, in the order given.\n for (const over of hosted.values()) {\n byId.set(\n over.id,\n untracked(() => bind(current, undefined, over)),\n );\n }\n return byId;\n });\n\n return {\n get: (id) => bound().get(id),\n all: computed(() => [...bound().values()]),\n state,\n };\n}\n","import { Directive, booleanAttribute, computed, input } from '@angular/core';\nimport { EditorActions } from './actions';\n\n/**\n * Makes the host's own control the trigger of an editor action: a click runs\n * it, and the control says what the action's state is.\n *\n * <button mat-icon-button emailAction=\"bold\" [emailActionFrom]=\"actions\"\n * #bold=\"emailAction\" [disabled]=\"bold.disabled()\">\n * <mat-icon>format_bold</mat-icon>\n * </button>\n *\n * The action is named by its id, and looked up in the list it is from\n * (`injectActions`) here, in a `computed`: a template binds values and reads\n * signals, it calls no lookup of its own.\n *\n * Behaviour only, and ARIA only where the host's widget has not spoken:\n * - `aria-pressed` for a toggle, and `aria-disabled` when it cannot run —\n * both off with `[emailActionAria]=\"false\"` for a widget that writes its own\n * (a Material button toggle);\n * - never the native `disabled`, a class or a style: how disabled *looks* is\n * the host's, bound from `disabled()` as above. A control that is only\n * `aria-disabled` stays reachable by keyboard, which is what a toolbar wants;\n * - a click on a disabled trigger runs nothing.\n *\n * After running, the caret goes back to the editor the action ran on — a\n * no-op for a pointer press under `emailKeepFocus`, the way back for a key\n * press in a toolbar. `[emailActionFocus]=\"false\"` leaves focus on the\n * control, as the ARIA toolbar pattern has it. A host's own action (a link\n * dialog, a picker) never has focus taken from what it opened.\n */\n@Directive({\n selector: '[emailAction]',\n exportAs: 'emailAction',\n host: {\n '[attr.aria-pressed]': 'ariaPressed()',\n '[attr.aria-disabled]': 'ariaDisabled()',\n '(click)': 'run()',\n },\n})\nexport class ActionTrigger {\n /** The id of the action to trigger. */\n readonly id = input.required<string>({ alias: 'emailAction' });\n\n /** The actions it is one of — what `injectActions` returned. */\n readonly from = input.required<EditorActions>({ alias: 'emailActionFrom' });\n\n /** The action itself. `undefined` (no editor yet, or a kit without it) is a\n trigger with nothing to do: disabled. */\n readonly action = computed(() => this.from().get(this.id()));\n\n /** Whether this directive writes `aria-pressed` and `aria-disabled`. */\n readonly aria = input(true, { alias: 'emailActionAria', transform: booleanAttribute });\n\n /** Whether the caret returns to the editor after the action ran. */\n readonly returnFocus = input(true, { alias: 'emailActionFocus', transform: booleanAttribute });\n\n /** On at the selection. */\n readonly pressed = computed(() => this.action()?.pressed() ?? false);\n\n /** Cannot run right now — or has no action at all. */\n readonly disabled = computed(() => this.action()?.disabled() ?? true);\n\n protected readonly ariaPressed = computed(() =>\n this.aria() && this.action()?.toggles ? this.pressed() : null,\n );\n\n protected readonly ariaDisabled = computed(() => (this.aria() && this.disabled() ? true : null));\n\n /** Runs the action, as a click does. False when it did not apply. */\n run(): boolean {\n const action = this.action();\n if (!action || this.disabled()) return false;\n const applied = action.run();\n // A host's own action opened something of the host's: focus is its now.\n if (this.returnFocus() && !action.external) action.focus();\n return applied;\n }\n}\n","/*\n * Public API Surface of @h-k-dev/angular-email-editor/actions\n */\n\nexport * from './actions';\nexport * from './action-trigger';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -332,15 +332,14 @@ class AddressInput {
332
332
  /** The chips as rendered, for the commands that are the chip's own. */
333
333
  chips = viewChildren(AddressChip, /* @ts-ignore */
334
334
  ...(ngDevMode ? [{ debugName: "chips" }] : /* istanbul ignore next */ []));
335
+ /** What a chip's id starts with; its index ends it. */
336
+ chipIdPrefix = `${this.id}-chip-`;
335
337
  /** The active chip's id, for the input's `aria-activedescendant`. */
336
338
  activeId = computed(() => {
337
339
  const index = this.active();
338
- return index !== null && index < this.value().length ? this.chipId(index) : null;
340
+ return index !== null && index < this.value().length ? this.chipIdPrefix + index : null;
339
341
  }, /* @ts-ignore */
340
342
  ...(ngDevMode ? [{ debugName: "activeId" }] : /* istanbul ignore next */ []));
341
- chipId(index) {
342
- return `${this.id}-chip-${index}`;
343
- }
344
343
  /** The cap is reached: a further address is refused. */
345
344
  full = computed(() => this.value().length >= this.limit(), /* @ts-ignore */
346
345
  ...(ngDevMode ? [{ debugName: "full" }] : /* istanbul ignore next */ []));
@@ -1005,7 +1004,7 @@ class AddressInput {
1005
1004
  return !!destination && this.#host.nativeElement.contains(destination);
1006
1005
  }
1007
1006
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: AddressInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
1008
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: AddressInput, isStandalone: true, selector: "[email-address-input]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedby: { classPropertyName: "ariaDescribedby", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, limit: { classPropertyName: "limit", publicName: "limit", isSignal: true, isRequired: false, transformFunction: null }, removeLabel: { classPropertyName: "removeLabel", publicName: "removeLabel", isSignal: true, isRequired: false, transformFunction: null }, invalidLabel: { classPropertyName: "invalidLabel", publicName: "invalidLabel", isSignal: true, isRequired: false, transformFunction: null }, pendingLabel: { classPropertyName: "pendingLabel", publicName: "pendingLabel", isSignal: true, isRequired: false, transformFunction: null }, movedLabel: { classPropertyName: "movedLabel", publicName: "movedLabel", isSignal: true, isRequired: false, transformFunction: null }, allowDrag: { classPropertyName: "allowDrag", publicName: "allowDrag", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { listeners: { "pointerdown": "onPointerdown($event)", "mousedown": "keepCaret($event)", "click": "focus()", "focusin": "onFocusin()", "focusout": "onFocusout($event)", "dragenter": "onDragover($event)", "dragover": "onDragover($event)", "dragleave": "onDragleave($event)", "drop": "onDrop($event)" }, properties: { "attr.aria-disabled": "disabled() || null", "attr.data-invalid": "flagged() || null", "attr.data-full": "full() || null", "attr.data-focused": "focused() || null", "attr.data-dropping": "dropping() || null" } }, queries: [{ propertyName: "labelSlot", first: true, predicate: AddressInputLabel, descendants: true, isSignal: true }, { propertyName: "removeSlot", first: true, predicate: AddressChipRemove, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "field", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "chipList", first: true, predicate: ["chipList"], descendants: true, isSignal: true }, { propertyName: "chips", predicate: AddressChip, descendants: true, isSignal: true }], ngImport: i0, template: "<!-- No label here: the row around this control names it, through\n aria-labelledby or aria-label, both passed down to the text input. -->\n<!-- Focusable by script and by a press only (tabindex -1, while chips can\n be dragged): a press on a draggable chip must keep its default for the\n drag to start, and its focus lands here \u2014 inside the control. -->\n<ul #chipList data-slot=\"chips\" role=\"list\" [attr.tabindex]=\"canDrag() ? -1 : null\">\n <!-- The opt-in label (emailAddressLabel): first in the row, so the chips\n wrap under it. Hidden from assistive tech as text \u2014 it names the\n text input instead, through aria-labelledby. -->\n @if (labelSlot(); as slot) {\n <li data-slot=\"label\" aria-hidden=\"true\" [id]=\"labelId\">\n <ng-container [ngTemplateOutlet]=\"slot.template\" />\n </li>\n }\n @for (address of value(); track address) {\n <li\n email-address-chip\n [id]=\"chipId($index)\"\n [address]=\"address\"\n [removable]=\"!locked()\"\n [inline]=\"!focused()\"\n [draggable]=\"canDrag()\"\n [aria-current]=\"active() === $index\"\n [removeTabbable]=\"closed()\"\n [removeLabel]=\"removeLabel()\"\n [removeTemplate]=\"removeSlot()?.template ?? null\"\n [invalidLabel]=\"invalidLabel()\"\n [pendingLabel]=\"pendingLabel()\"\n [aria-disabled]=\"disabled()\"\n (removed)=\"removeChip(address)\"\n (copied)=\"onChipCopied($event)\"\n (click)=\"onChipClick($event, $index, field)\"\n (dblclick)=\"onChipDblclick($event, address, field)\"\n (dragstart)=\"onChipDragstart(address)\"\n (dragend)=\"onChipDragend()\"\n ></li>\n }\n <!-- Where a drag over the control would land: a line between entries,\n drawn on top and out of the flow \u2014 nothing moves under the pointer. -->\n @if (dropMarker(); as marker) {\n <li\n data-slot=\"drop-marker\"\n aria-hidden=\"true\"\n [style.left.px]=\"marker.x\"\n [style.top.px]=\"marker.y\"\n [style.height.px]=\"marker.height\"\n ></li>\n }\n <!-- The entry is a list item too, so the chips and the typing sit in one\n wrapping row \u2014 always after the last chip. Hidden once the field is full (From takes one address)\n with nothing to fix: the chips say everything, and a second address\n would only be refused. -->\n <li data-slot=\"entry\" [hidden]=\"closed()\">\n <input\n #field\n data-slot=\"input\"\n type=\"text\"\n inputmode=\"email\"\n autocomplete=\"off\"\n autocapitalize=\"off\"\n spellcheck=\"false\"\n [id]=\"id\"\n [attr.name]=\"name() || null\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [placeholder]=\"value().length ? '' : placeholder()\"\n [attr.aria-labelledby]=\"labelledBy()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"flagged() || refused() || null\"\n [attr.aria-activedescendant]=\"activeId()\"\n [attr.data-refused]=\"refused() || null\"\n (keydown)=\"onKeydown($event, field)\"\n (paste)=\"onPaste($event, field)\"\n (copy)=\"onClipboard($event, field, false)\"\n (cut)=\"onClipboard($event, field, true)\"\n (input)=\"onInput(field)\"\n (mousedown)=\"active.set(null)\"\n (focus)=\"onFocus(field)\"\n (blur)=\"onBlur($event, field)\"\n />\n </li>\n</ul>\n", styles: [":host{display:flex;min-width:0;color:var(--email-address-input-color, var(--mat-sys-on-surface, light-dark(#1f1f1f, #e3e3e3)));font-family:var(--email-address-input-font-family, var(--mat-sys-body-medium-font, system-ui, sans-serif));font-size:var(--email-address-input-font-size, var(--mat-sys-body-medium-size, .875rem));font-weight:var(--email-address-input-font-weight, var(--mat-sys-body-medium-weight, 400));line-height:var(--email-address-input-line-height, var(--mat-sys-body-medium-line-height, 1.25rem));letter-spacing:var(--email-address-input-letter-spacing, var(--mat-sys-body-medium-tracking, .016rem));cursor:text}:host([aria-disabled=true]){cursor:default;opacity:.6}:host :where([data-slot=chips]){position:relative;flex:1 1 0;display:flex;flex-wrap:wrap;align-items:center;gap:var(--email-address-input-row-gap, 8px) var(--email-address-input-column-gap, 4px);min-width:0;margin:0;padding:0;list-style:none}:host :where([data-slot=chips]):focus{outline:none}:host :where([data-slot=drop-marker]){position:absolute;box-sizing:content-box;margin-top:calc(-1 * var(--email-address-input-drop-overhang, 4px));padding-block:var(--email-address-input-drop-overhang, 4px);width:var(--email-address-input-drop-width, 2px);margin-left:calc(var(--email-address-input-drop-width, 2px) / -2);border-radius:1px;background:var(--email-address-input-drop-color, var(--mat-sys-primary, light-dark(#0b57d0, #a8c7fa)));pointer-events:none}:host :where([data-slot=label]){flex:none;margin-inline-end:var(--email-address-input-label-gap, 4px);color:var(--email-address-input-label-color, var(--mat-sys-on-surface-variant, light-dark(#444746, #c4c7c5)));line-height:var(--email-address-input-label-line-height, 24px);white-space:nowrap}:host(:not([data-focused])) :where([data-slot=chips]){column-gap:var(--email-address-input-inline-gap, .3em)}:host(:not([data-focused])) :where([email-address-chip]:has(+[email-address-chip])):after{content:\",\"}:host :where([data-slot=entry]){flex:1 1 8ch;min-width:8ch;display:flex}:host :where([data-slot=entry][hidden]){display:none}:host(:not([data-focused])) :where([data-slot=entry]){flex-basis:0;min-width:0}:host :where([data-slot=input]){flex:1 1 auto;width:100%;min-width:0;height:var(--email-address-chip-height, 24px);margin:0;padding:0;box-sizing:border-box;border:none;outline:none;background:none;color:inherit;font:inherit;letter-spacing:inherit;line-height:var(--email-address-chip-height, 24px)}:host :where([data-slot=input][data-refused]){color:var(--email-address-chip-invalid-color, var(--mat-sys-error, light-dark(#b3261e, #f2b8b5)))}:host :where([data-slot=input])::placeholder{color:var(--email-address-input-placeholder-color, var(--mat-sys-on-surface-variant, light-dark(#5f6368, #9aa0a6)))}\n"], dependencies: [{ kind: "component", type: AddressChip, selector: "[email-address-chip]", inputs: ["address", "removable", "inline", "aria-current", "removeTabbable", "removeLabel", "invalidLabel", "pendingLabel", "aria-disabled", "holdDelay", "copiedLabel", "draggable", "removeTemplate"], outputs: ["removed", "copied"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
1007
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: AddressInput, isStandalone: true, selector: "[email-address-input]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedby: { classPropertyName: "ariaDescribedby", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, limit: { classPropertyName: "limit", publicName: "limit", isSignal: true, isRequired: false, transformFunction: null }, removeLabel: { classPropertyName: "removeLabel", publicName: "removeLabel", isSignal: true, isRequired: false, transformFunction: null }, invalidLabel: { classPropertyName: "invalidLabel", publicName: "invalidLabel", isSignal: true, isRequired: false, transformFunction: null }, pendingLabel: { classPropertyName: "pendingLabel", publicName: "pendingLabel", isSignal: true, isRequired: false, transformFunction: null }, movedLabel: { classPropertyName: "movedLabel", publicName: "movedLabel", isSignal: true, isRequired: false, transformFunction: null }, allowDrag: { classPropertyName: "allowDrag", publicName: "allowDrag", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { listeners: { "pointerdown": "onPointerdown($event)", "mousedown": "keepCaret($event)", "click": "focus()", "focusin": "onFocusin()", "focusout": "onFocusout($event)", "dragenter": "onDragover($event)", "dragover": "onDragover($event)", "dragleave": "onDragleave($event)", "drop": "onDrop($event)" }, properties: { "attr.aria-disabled": "disabled() || null", "attr.data-invalid": "flagged() || null", "attr.data-full": "full() || null", "attr.data-focused": "focused() || null", "attr.data-dropping": "dropping() || null" } }, queries: [{ propertyName: "labelSlot", first: true, predicate: AddressInputLabel, descendants: true, isSignal: true }, { propertyName: "removeSlot", first: true, predicate: AddressChipRemove, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "field", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "chipList", first: true, predicate: ["chipList"], descendants: true, isSignal: true }, { propertyName: "chips", predicate: AddressChip, descendants: true, isSignal: true }], ngImport: i0, template: "<!-- No label here: the row around this control names it, through\n aria-labelledby or aria-label, both passed down to the text input. -->\n<!-- Focusable by script and by a press only (tabindex -1, while chips can\n be dragged): a press on a draggable chip must keep its default for the\n drag to start, and its focus lands here \u2014 inside the control. -->\n<ul #chipList data-slot=\"chips\" role=\"list\" [attr.tabindex]=\"canDrag() ? -1 : null\">\n <!-- The opt-in label (emailAddressLabel): first in the row, so the chips\n wrap under it. Hidden from assistive tech as text \u2014 it names the\n text input instead, through aria-labelledby. -->\n @if (labelSlot(); as slot) {\n <li data-slot=\"label\" aria-hidden=\"true\" [id]=\"labelId\">\n <ng-container [ngTemplateOutlet]=\"slot.template\" />\n </li>\n }\n @for (address of value(); track address) {\n <li\n email-address-chip\n [id]=\"chipIdPrefix + $index\"\n [address]=\"address\"\n [removable]=\"!locked()\"\n [inline]=\"!focused()\"\n [draggable]=\"canDrag()\"\n [aria-current]=\"active() === $index\"\n [removeTabbable]=\"closed()\"\n [removeLabel]=\"removeLabel()\"\n [removeTemplate]=\"removeSlot()?.template ?? null\"\n [invalidLabel]=\"invalidLabel()\"\n [pendingLabel]=\"pendingLabel()\"\n [aria-disabled]=\"disabled()\"\n (removed)=\"removeChip(address)\"\n (copied)=\"onChipCopied($event)\"\n (click)=\"onChipClick($event, $index, field)\"\n (dblclick)=\"onChipDblclick($event, address, field)\"\n (dragstart)=\"onChipDragstart(address)\"\n (dragend)=\"onChipDragend()\"\n ></li>\n }\n <!-- Where a drag over the control would land: a line between entries,\n drawn on top and out of the flow \u2014 nothing moves under the pointer. -->\n @if (dropMarker(); as marker) {\n <li\n data-slot=\"drop-marker\"\n aria-hidden=\"true\"\n [style.left.px]=\"marker.x\"\n [style.top.px]=\"marker.y\"\n [style.height.px]=\"marker.height\"\n ></li>\n }\n <!-- The entry is a list item too, so the chips and the typing sit in one\n wrapping row \u2014 always after the last chip. Hidden once the field is full (From takes one address)\n with nothing to fix: the chips say everything, and a second address\n would only be refused. -->\n <li data-slot=\"entry\" [hidden]=\"closed()\">\n <input\n #field\n data-slot=\"input\"\n type=\"text\"\n inputmode=\"email\"\n autocomplete=\"off\"\n autocapitalize=\"off\"\n spellcheck=\"false\"\n [id]=\"id\"\n [attr.name]=\"name() || null\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [placeholder]=\"value().length ? '' : placeholder()\"\n [attr.aria-labelledby]=\"labelledBy()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"flagged() || refused() || null\"\n [attr.aria-activedescendant]=\"activeId()\"\n [attr.data-refused]=\"refused() || null\"\n (keydown)=\"onKeydown($event, field)\"\n (paste)=\"onPaste($event, field)\"\n (copy)=\"onClipboard($event, field, false)\"\n (cut)=\"onClipboard($event, field, true)\"\n (input)=\"onInput(field)\"\n (mousedown)=\"active.set(null)\"\n (focus)=\"onFocus(field)\"\n (blur)=\"onBlur($event, field)\"\n />\n </li>\n</ul>\n", styles: [":host{display:flex;min-width:0;color:var(--email-address-input-color, var(--mat-sys-on-surface, light-dark(#1f1f1f, #e3e3e3)));font-family:var(--email-address-input-font-family, var(--mat-sys-body-medium-font, system-ui, sans-serif));font-size:var(--email-address-input-font-size, var(--mat-sys-body-medium-size, .875rem));font-weight:var(--email-address-input-font-weight, var(--mat-sys-body-medium-weight, 400));line-height:var(--email-address-input-line-height, var(--mat-sys-body-medium-line-height, 1.25rem));letter-spacing:var(--email-address-input-letter-spacing, var(--mat-sys-body-medium-tracking, .016rem));cursor:text}:host([aria-disabled=true]){cursor:default;opacity:.6}:host :where([data-slot=chips]){position:relative;flex:1 1 0;display:flex;flex-wrap:wrap;align-items:center;gap:var(--email-address-input-row-gap, 8px) var(--email-address-input-column-gap, 4px);min-width:0;margin:0;padding:0;list-style:none}:host :where([data-slot=chips]):focus{outline:none}:host :where([data-slot=drop-marker]){position:absolute;box-sizing:content-box;margin-top:calc(-1 * var(--email-address-input-drop-overhang, 4px));padding-block:var(--email-address-input-drop-overhang, 4px);width:var(--email-address-input-drop-width, 2px);margin-left:calc(var(--email-address-input-drop-width, 2px) / -2);border-radius:1px;background:var(--email-address-input-drop-color, var(--mat-sys-primary, light-dark(#0b57d0, #a8c7fa)));pointer-events:none}:host :where([data-slot=label]){flex:none;margin-inline-end:var(--email-address-input-label-gap, 4px);color:var(--email-address-input-label-color, var(--mat-sys-on-surface-variant, light-dark(#444746, #c4c7c5)));line-height:var(--email-address-input-label-line-height, 24px);white-space:nowrap}:host(:not([data-focused])) :where([data-slot=chips]){column-gap:var(--email-address-input-inline-gap, .3em)}:host(:not([data-focused])) :where([email-address-chip]:has(+[email-address-chip])):after{content:\",\"}:host :where([data-slot=entry]){flex:1 1 8ch;min-width:8ch;display:flex}:host :where([data-slot=entry][hidden]){display:none}:host(:not([data-focused])) :where([data-slot=entry]){flex-basis:0;min-width:0}:host :where([data-slot=input]){flex:1 1 auto;width:100%;min-width:0;height:var(--email-address-chip-height, 24px);margin:0;padding:0;box-sizing:border-box;border:none;outline:none;background:none;color:inherit;font:inherit;letter-spacing:inherit;line-height:var(--email-address-chip-height, 24px)}:host :where([data-slot=input][data-refused]){color:var(--email-address-chip-invalid-color, var(--mat-sys-error, light-dark(#b3261e, #f2b8b5)))}:host :where([data-slot=input])::placeholder{color:var(--email-address-input-placeholder-color, var(--mat-sys-on-surface-variant, light-dark(#5f6368, #9aa0a6)))}\n"], dependencies: [{ kind: "component", type: AddressChip, selector: "[email-address-chip]", inputs: ["address", "removable", "inline", "aria-current", "removeTabbable", "removeLabel", "invalidLabel", "pendingLabel", "aria-disabled", "holdDelay", "copiedLabel", "draggable", "removeTemplate"], outputs: ["removed", "copied"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
1009
1008
  }
1010
1009
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: AddressInput, decorators: [{
1011
1010
  type: Component,
@@ -1024,7 +1023,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
1024
1023
  '(dragover)': 'onDragover($event)',
1025
1024
  '(dragleave)': 'onDragleave($event)',
1026
1025
  '(drop)': 'onDrop($event)',
1027
- }, template: "<!-- No label here: the row around this control names it, through\n aria-labelledby or aria-label, both passed down to the text input. -->\n<!-- Focusable by script and by a press only (tabindex -1, while chips can\n be dragged): a press on a draggable chip must keep its default for the\n drag to start, and its focus lands here \u2014 inside the control. -->\n<ul #chipList data-slot=\"chips\" role=\"list\" [attr.tabindex]=\"canDrag() ? -1 : null\">\n <!-- The opt-in label (emailAddressLabel): first in the row, so the chips\n wrap under it. Hidden from assistive tech as text \u2014 it names the\n text input instead, through aria-labelledby. -->\n @if (labelSlot(); as slot) {\n <li data-slot=\"label\" aria-hidden=\"true\" [id]=\"labelId\">\n <ng-container [ngTemplateOutlet]=\"slot.template\" />\n </li>\n }\n @for (address of value(); track address) {\n <li\n email-address-chip\n [id]=\"chipId($index)\"\n [address]=\"address\"\n [removable]=\"!locked()\"\n [inline]=\"!focused()\"\n [draggable]=\"canDrag()\"\n [aria-current]=\"active() === $index\"\n [removeTabbable]=\"closed()\"\n [removeLabel]=\"removeLabel()\"\n [removeTemplate]=\"removeSlot()?.template ?? null\"\n [invalidLabel]=\"invalidLabel()\"\n [pendingLabel]=\"pendingLabel()\"\n [aria-disabled]=\"disabled()\"\n (removed)=\"removeChip(address)\"\n (copied)=\"onChipCopied($event)\"\n (click)=\"onChipClick($event, $index, field)\"\n (dblclick)=\"onChipDblclick($event, address, field)\"\n (dragstart)=\"onChipDragstart(address)\"\n (dragend)=\"onChipDragend()\"\n ></li>\n }\n <!-- Where a drag over the control would land: a line between entries,\n drawn on top and out of the flow \u2014 nothing moves under the pointer. -->\n @if (dropMarker(); as marker) {\n <li\n data-slot=\"drop-marker\"\n aria-hidden=\"true\"\n [style.left.px]=\"marker.x\"\n [style.top.px]=\"marker.y\"\n [style.height.px]=\"marker.height\"\n ></li>\n }\n <!-- The entry is a list item too, so the chips and the typing sit in one\n wrapping row \u2014 always after the last chip. Hidden once the field is full (From takes one address)\n with nothing to fix: the chips say everything, and a second address\n would only be refused. -->\n <li data-slot=\"entry\" [hidden]=\"closed()\">\n <input\n #field\n data-slot=\"input\"\n type=\"text\"\n inputmode=\"email\"\n autocomplete=\"off\"\n autocapitalize=\"off\"\n spellcheck=\"false\"\n [id]=\"id\"\n [attr.name]=\"name() || null\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [placeholder]=\"value().length ? '' : placeholder()\"\n [attr.aria-labelledby]=\"labelledBy()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"flagged() || refused() || null\"\n [attr.aria-activedescendant]=\"activeId()\"\n [attr.data-refused]=\"refused() || null\"\n (keydown)=\"onKeydown($event, field)\"\n (paste)=\"onPaste($event, field)\"\n (copy)=\"onClipboard($event, field, false)\"\n (cut)=\"onClipboard($event, field, true)\"\n (input)=\"onInput(field)\"\n (mousedown)=\"active.set(null)\"\n (focus)=\"onFocus(field)\"\n (blur)=\"onBlur($event, field)\"\n />\n </li>\n</ul>\n", styles: [":host{display:flex;min-width:0;color:var(--email-address-input-color, var(--mat-sys-on-surface, light-dark(#1f1f1f, #e3e3e3)));font-family:var(--email-address-input-font-family, var(--mat-sys-body-medium-font, system-ui, sans-serif));font-size:var(--email-address-input-font-size, var(--mat-sys-body-medium-size, .875rem));font-weight:var(--email-address-input-font-weight, var(--mat-sys-body-medium-weight, 400));line-height:var(--email-address-input-line-height, var(--mat-sys-body-medium-line-height, 1.25rem));letter-spacing:var(--email-address-input-letter-spacing, var(--mat-sys-body-medium-tracking, .016rem));cursor:text}:host([aria-disabled=true]){cursor:default;opacity:.6}:host :where([data-slot=chips]){position:relative;flex:1 1 0;display:flex;flex-wrap:wrap;align-items:center;gap:var(--email-address-input-row-gap, 8px) var(--email-address-input-column-gap, 4px);min-width:0;margin:0;padding:0;list-style:none}:host :where([data-slot=chips]):focus{outline:none}:host :where([data-slot=drop-marker]){position:absolute;box-sizing:content-box;margin-top:calc(-1 * var(--email-address-input-drop-overhang, 4px));padding-block:var(--email-address-input-drop-overhang, 4px);width:var(--email-address-input-drop-width, 2px);margin-left:calc(var(--email-address-input-drop-width, 2px) / -2);border-radius:1px;background:var(--email-address-input-drop-color, var(--mat-sys-primary, light-dark(#0b57d0, #a8c7fa)));pointer-events:none}:host :where([data-slot=label]){flex:none;margin-inline-end:var(--email-address-input-label-gap, 4px);color:var(--email-address-input-label-color, var(--mat-sys-on-surface-variant, light-dark(#444746, #c4c7c5)));line-height:var(--email-address-input-label-line-height, 24px);white-space:nowrap}:host(:not([data-focused])) :where([data-slot=chips]){column-gap:var(--email-address-input-inline-gap, .3em)}:host(:not([data-focused])) :where([email-address-chip]:has(+[email-address-chip])):after{content:\",\"}:host :where([data-slot=entry]){flex:1 1 8ch;min-width:8ch;display:flex}:host :where([data-slot=entry][hidden]){display:none}:host(:not([data-focused])) :where([data-slot=entry]){flex-basis:0;min-width:0}:host :where([data-slot=input]){flex:1 1 auto;width:100%;min-width:0;height:var(--email-address-chip-height, 24px);margin:0;padding:0;box-sizing:border-box;border:none;outline:none;background:none;color:inherit;font:inherit;letter-spacing:inherit;line-height:var(--email-address-chip-height, 24px)}:host :where([data-slot=input][data-refused]){color:var(--email-address-chip-invalid-color, var(--mat-sys-error, light-dark(#b3261e, #f2b8b5)))}:host :where([data-slot=input])::placeholder{color:var(--email-address-input-placeholder-color, var(--mat-sys-on-surface-variant, light-dark(#5f6368, #9aa0a6)))}\n"] }]
1026
+ }, template: "<!-- No label here: the row around this control names it, through\n aria-labelledby or aria-label, both passed down to the text input. -->\n<!-- Focusable by script and by a press only (tabindex -1, while chips can\n be dragged): a press on a draggable chip must keep its default for the\n drag to start, and its focus lands here \u2014 inside the control. -->\n<ul #chipList data-slot=\"chips\" role=\"list\" [attr.tabindex]=\"canDrag() ? -1 : null\">\n <!-- The opt-in label (emailAddressLabel): first in the row, so the chips\n wrap under it. Hidden from assistive tech as text \u2014 it names the\n text input instead, through aria-labelledby. -->\n @if (labelSlot(); as slot) {\n <li data-slot=\"label\" aria-hidden=\"true\" [id]=\"labelId\">\n <ng-container [ngTemplateOutlet]=\"slot.template\" />\n </li>\n }\n @for (address of value(); track address) {\n <li\n email-address-chip\n [id]=\"chipIdPrefix + $index\"\n [address]=\"address\"\n [removable]=\"!locked()\"\n [inline]=\"!focused()\"\n [draggable]=\"canDrag()\"\n [aria-current]=\"active() === $index\"\n [removeTabbable]=\"closed()\"\n [removeLabel]=\"removeLabel()\"\n [removeTemplate]=\"removeSlot()?.template ?? null\"\n [invalidLabel]=\"invalidLabel()\"\n [pendingLabel]=\"pendingLabel()\"\n [aria-disabled]=\"disabled()\"\n (removed)=\"removeChip(address)\"\n (copied)=\"onChipCopied($event)\"\n (click)=\"onChipClick($event, $index, field)\"\n (dblclick)=\"onChipDblclick($event, address, field)\"\n (dragstart)=\"onChipDragstart(address)\"\n (dragend)=\"onChipDragend()\"\n ></li>\n }\n <!-- Where a drag over the control would land: a line between entries,\n drawn on top and out of the flow \u2014 nothing moves under the pointer. -->\n @if (dropMarker(); as marker) {\n <li\n data-slot=\"drop-marker\"\n aria-hidden=\"true\"\n [style.left.px]=\"marker.x\"\n [style.top.px]=\"marker.y\"\n [style.height.px]=\"marker.height\"\n ></li>\n }\n <!-- The entry is a list item too, so the chips and the typing sit in one\n wrapping row \u2014 always after the last chip. Hidden once the field is full (From takes one address)\n with nothing to fix: the chips say everything, and a second address\n would only be refused. -->\n <li data-slot=\"entry\" [hidden]=\"closed()\">\n <input\n #field\n data-slot=\"input\"\n type=\"text\"\n inputmode=\"email\"\n autocomplete=\"off\"\n autocapitalize=\"off\"\n spellcheck=\"false\"\n [id]=\"id\"\n [attr.name]=\"name() || null\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [placeholder]=\"value().length ? '' : placeholder()\"\n [attr.aria-labelledby]=\"labelledBy()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"flagged() || refused() || null\"\n [attr.aria-activedescendant]=\"activeId()\"\n [attr.data-refused]=\"refused() || null\"\n (keydown)=\"onKeydown($event, field)\"\n (paste)=\"onPaste($event, field)\"\n (copy)=\"onClipboard($event, field, false)\"\n (cut)=\"onClipboard($event, field, true)\"\n (input)=\"onInput(field)\"\n (mousedown)=\"active.set(null)\"\n (focus)=\"onFocus(field)\"\n (blur)=\"onBlur($event, field)\"\n />\n </li>\n</ul>\n", styles: [":host{display:flex;min-width:0;color:var(--email-address-input-color, var(--mat-sys-on-surface, light-dark(#1f1f1f, #e3e3e3)));font-family:var(--email-address-input-font-family, var(--mat-sys-body-medium-font, system-ui, sans-serif));font-size:var(--email-address-input-font-size, var(--mat-sys-body-medium-size, .875rem));font-weight:var(--email-address-input-font-weight, var(--mat-sys-body-medium-weight, 400));line-height:var(--email-address-input-line-height, var(--mat-sys-body-medium-line-height, 1.25rem));letter-spacing:var(--email-address-input-letter-spacing, var(--mat-sys-body-medium-tracking, .016rem));cursor:text}:host([aria-disabled=true]){cursor:default;opacity:.6}:host :where([data-slot=chips]){position:relative;flex:1 1 0;display:flex;flex-wrap:wrap;align-items:center;gap:var(--email-address-input-row-gap, 8px) var(--email-address-input-column-gap, 4px);min-width:0;margin:0;padding:0;list-style:none}:host :where([data-slot=chips]):focus{outline:none}:host :where([data-slot=drop-marker]){position:absolute;box-sizing:content-box;margin-top:calc(-1 * var(--email-address-input-drop-overhang, 4px));padding-block:var(--email-address-input-drop-overhang, 4px);width:var(--email-address-input-drop-width, 2px);margin-left:calc(var(--email-address-input-drop-width, 2px) / -2);border-radius:1px;background:var(--email-address-input-drop-color, var(--mat-sys-primary, light-dark(#0b57d0, #a8c7fa)));pointer-events:none}:host :where([data-slot=label]){flex:none;margin-inline-end:var(--email-address-input-label-gap, 4px);color:var(--email-address-input-label-color, var(--mat-sys-on-surface-variant, light-dark(#444746, #c4c7c5)));line-height:var(--email-address-input-label-line-height, 24px);white-space:nowrap}:host(:not([data-focused])) :where([data-slot=chips]){column-gap:var(--email-address-input-inline-gap, .3em)}:host(:not([data-focused])) :where([email-address-chip]:has(+[email-address-chip])):after{content:\",\"}:host :where([data-slot=entry]){flex:1 1 8ch;min-width:8ch;display:flex}:host :where([data-slot=entry][hidden]){display:none}:host(:not([data-focused])) :where([data-slot=entry]){flex-basis:0;min-width:0}:host :where([data-slot=input]){flex:1 1 auto;width:100%;min-width:0;height:var(--email-address-chip-height, 24px);margin:0;padding:0;box-sizing:border-box;border:none;outline:none;background:none;color:inherit;font:inherit;letter-spacing:inherit;line-height:var(--email-address-chip-height, 24px)}:host :where([data-slot=input][data-refused]){color:var(--email-address-chip-invalid-color, var(--mat-sys-error, light-dark(#b3261e, #f2b8b5)))}:host :where([data-slot=input])::placeholder{color:var(--email-address-input-placeholder-color, var(--mat-sys-on-surface-variant, light-dark(#5f6368, #9aa0a6)))}\n"] }]
1028
1027
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], ariaLabelledby: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-labelledby", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], ariaDescribedby: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-describedby", required: false }] }], limit: [{ type: i0.Input, args: [{ isSignal: true, alias: "limit", required: false }] }], removeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeLabel", required: false }] }], invalidLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidLabel", required: false }] }], pendingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "pendingLabel", required: false }] }], movedLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "movedLabel", required: false }] }], allowDrag: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowDrag", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], labelSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => AddressInputLabel), { isSignal: true }] }], removeSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => AddressChipRemove), { isSignal: true }] }], field: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], chipList: [{ type: i0.ViewChild, args: ['chipList', { isSignal: true }] }], chips: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => AddressChip), { isSignal: true }] }] } });
1029
1028
 
1030
1029
  /** The error kinds `addressList` reports, for a host that switches on them. */