@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.
@@ -240,11 +240,26 @@ class SuggestionMenu {
240
240
  // Placing the box: after its rows are rendered, measured in one phase and
241
241
  // written in the next — the plugin never touches the element, so no read
242
242
  // follows a write inside a keystroke. Shown only once it is in place.
243
+ //
244
+ // A box that fits on neither side of the line is shrunk to the side with
245
+ // more room. The cap goes on the listbox, not the box: the box keeps its
246
+ // own max-height (the --email-suggestion-menu-max-height token) to be
247
+ // read, and its height without the cap is its rendered height plus what
248
+ // the capped list hides — a box measured at its last cap would choose its
249
+ // side by the old room and flip back and forth.
243
250
  afterRenderEffect({
244
251
  earlyRead: () => {
245
252
  const layout = this.#layout();
246
253
  const anchor = layout?.clientRect();
247
- return layout && anchor ? measureMenuPlacement(anchor, this.#host, layout.offset) : null;
254
+ if (!layout || !anchor)
255
+ return null;
256
+ const list = this.listbox().nativeElement;
257
+ const rendered = this.#host.offsetHeight;
258
+ const cap = parseFloat(getComputedStyle(this.#host).maxHeight);
259
+ const full = rendered + list.scrollHeight - list.clientHeight;
260
+ const height = cap >= 0 ? Math.min(full, cap) : full;
261
+ const place = measureMenuPlacement(anchor, this.#host, layout.offset, height);
262
+ return place && { ...place, chrome: rendered - list.offsetHeight };
248
263
  },
249
264
  write: (placement) => {
250
265
  const place = placement();
@@ -253,10 +268,14 @@ class SuggestionMenu {
253
268
  if (place) {
254
269
  const left = `${place.left}px`;
255
270
  const top = `${place.top}px`;
271
+ const listHeight = place.maxHeight === null ? '' : `${Math.max(place.maxHeight - place.chrome, 0)}px`;
272
+ const list = this.listbox().nativeElement.style;
256
273
  if (style.left !== left)
257
274
  style.left = left;
258
275
  if (style.top !== top)
259
276
  style.top = top;
277
+ if (list.maxHeight !== listHeight)
278
+ list.maxHeight = listHeight;
260
279
  }
261
280
  if (style.visibility !== visibility)
262
281
  style.visibility = visibility;
@@ -1 +1 @@
1
- {"version":3,"file":"h-k-dev-angular-email-editor-suggestion-menu.mjs","sources":["../../../projects/angular-email-editor/suggestion-menu/suggestion-menu.slots.ts","../../../projects/angular-email-editor/suggestion-menu/suggestion-menu.ts","../../../projects/angular-email-editor/suggestion-menu/suggestion-menu.html","../../../projects/angular-email-editor/suggestion-menu/suggestion-menu-item.ts","../../../projects/angular-email-editor/suggestion-menu/suggestion-menu-section.ts","../../../projects/angular-email-editor/suggestion-menu/public-api.ts","../../../projects/angular-email-editor/suggestion-menu/h-k-dev-angular-email-editor-suggestion-menu.ts"],"sourcesContent":["import { Directive, TemplateRef, inject } from '@angular/core';\nimport { SuggestionGroup } from '@h-k-dev/angular-email-editor';\n\n/**\n * A suggestion menu's header slot, shown on level 2 above the group's\n * children. The default is a back button and the group's title; a host\n * that wants its own — a Material icon button, the group's icon, a\n * breadcrumb — hands the menu a template:\n *\n * <div email-suggestion-menu [state]=\"state()\">\n * <ng-template emailSuggestionMenuHeader let-group let-back=\"back\" let-label=\"backLabel\">\n * <button mat-icon-button tabindex=\"-1\" [attr.aria-label]=\"label\" (click)=\"back()\">\n * <mat-icon>arrow_back</mat-icon>\n * </button>\n * {{ group.title }}\n * </ng-template>\n * …\n * </div>\n *\n * The template renders inside the menu's own `header` box.\n */\n\n/** What the header template is given. */\nexport interface SuggestionMenuHeaderContext {\n /** The group whose children are listed — its title already translated. */\n readonly $implicit: SuggestionGroup;\n /** Back to level 1 with an empty query. */\n readonly back: () => void;\n /** The back control's accessible name, as the menu was given it. */\n readonly backLabel: string;\n}\n\n/** Marks the `ng-template` the menu renders as its level-2 header. */\n@Directive({ selector: 'ng-template[emailSuggestionMenuHeader]' })\nexport class SuggestionMenuHeader {\n readonly template = inject<TemplateRef<SuggestionMenuHeaderContext>>(TemplateRef);\n\n static ngTemplateContextGuard(\n _directive: SuggestionMenuHeader,\n context: unknown,\n ): context is SuggestionMenuHeaderContext {\n return true;\n }\n}\n","import {\n Component,\n DestroyRef,\n ElementRef,\n inject,\n\n // Signals\n afterRenderEffect,\n computed,\n contentChild,\n debounced,\n input,\n linkedSignal,\n viewChild,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { SuggestionItem, SuggestionMenuState, measureMenuPlacement } from '@h-k-dev/angular-email-editor';\nimport { SuggestionMenuHeader, SuggestionMenuHeaderContext } from './suggestion-menu.slots';\n\n/**\n * A suggestion menu's floating box — the element `createSuggestionMenu` is\n * given, rendered from the state it reports. The extension does the work\n * (finding the trigger, filtering, paging, the keys, placing the box,\n * applying); this gives the state its roles and ids, so the editor's\n * `aria-controls` and `aria-activedescendant` land on real elements, keeps\n * the next page coming as the list scrolls, and says what is going on.\n *\n * **The pair.** The menu is the container; the host renders one\n * `[email-suggestion-menu-item]` per item into it and decides what a row\n * shows (an icon, the title, a detail). Rows are options of the menu's\n * listbox and never take focus: the caret stays in the editor, which is the\n * combobox. One pair serves every trigger — `/`, `{{`, `||` — at once: they\n * never open together, so a menu of several triggers is still one element\n * and one state, which says whose list it is (`trigger`, `label`).\n *\n * <div email-suggestion-menu #menu [state]=\"state()\">\n * @for (item of state()?.items; track item.id) {\n * <div email-suggestion-menu-item [item]=\"item\">{{ item.title }}</div>\n * }\n * </div>\n *\n * createSuggestionMenu({ element: menu, onChange: (s) => state.set(s), triggers: [\n * { trigger: '/', label: 'Insert block', items: extensionSuggestions },\n * { trigger: '{{', label: 'Tokens', source: fetchMergeTags },\n * ] })\n *\n * **Two levels.** Inside a group the menu shows a header above the list — a\n * back button and the group's title by default, or the host's\n * `ng-template[emailSuggestionMenuHeader]` — names the listbox after the\n * group, and says \"No results\" rather than closing when nothing matches.\n *\n * **Said twice, differently.** What is going on shows as a line under the\n * list, at once. A screen reader hears it from a separate live region that\n * waits for the typing to settle (`announceDelay`) and also counts the\n * results — the highlighted option's id does not change when the list is\n * filtered under it, so nothing else would say the list is a new one.\n *\n * Every word it says is an input, English by default.\n */\n@Component({\n selector: '[email-suggestion-menu]',\n imports: [NgTemplateOutlet],\n templateUrl: './suggestion-menu.html',\n styleUrl: './suggestion-menu.scss',\n host: {\n '[attr.data-level]': 'state()?.level ?? 1',\n },\n})\nexport class SuggestionMenu {\n /** The extension's latest state — undefined before the editor mounts. */\n readonly state = input<SuggestionMenuState>();\n\n /** Names the listbox on level 1 when the open trigger has no `label` of\n its own — a menu of several triggers names each list there (\"Insert\n block\", \"Personalization tokens\"); level 2 is named by its group. */\n readonly label = input('Suggestions');\n /** The level-2 back button's accessible name. */\n readonly backLabel = input('Back');\n /** Said while a source is still searching. */\n readonly loadingLabel = input('Searching…');\n /** Said on level 2 when nothing matches. */\n readonly emptyLabel = input('No results');\n /** Said while a further page is on its way. */\n readonly loadingMoreLabel = input('Loading more…');\n /** Said when the source's answer failed. */\n readonly errorLabel = input('Couldn’t load suggestions');\n /** Announced once a list is in: how many rows it has. */\n readonly resultsLabel = input<(count: number) => string>((count) =>\n count === 1 ? '1 result' : `${count} results`,\n );\n /** Milliseconds the announcement waits for the typing to settle, so a\n screen reader hears the list that stayed, not one per letter. Going\n quiet (the menu closes) never waits. 0 announces at once. */\n readonly announceDelay = input(400);\n /** Gap between the trigger's line and the menu, in px. */\n readonly offset = input(4);\n\n readonly #host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n\n /** The state's list. The extension reports a new state for every arrow\n press but the same list until it changes — so what hangs off the list\n (the index below, every row's position) sits an arrow press out. */\n readonly #items = computed(() => this.state()?.items);\n\n /** Each item's position in the list, looked up once per list — rows ask\n by identity, so a list of n rows costs n lookups, not n². */\n readonly #indices = computed(\n () => new Map(this.#items()?.map((item, index) => [item, index]) ?? []),\n );\n\n /** The keyboard-highlighted row's index; -1 before there is a state. */\n readonly activeIndex = computed(() => this.state()?.activeIndex ?? -1);\n\n /** The extension's id for the option at an index — the same function for\n the menu's whole life. */\n readonly optionId = computed(() => this.state()?.optionId);\n\n /** Where `item` sits in the current list; -1 when it is not in it. */\n indexOf(item: SuggestionItem): number {\n return this.#indices().get(item) ?? -1;\n }\n\n protected readonly header = contentChild(SuggestionMenuHeader);\n protected readonly listbox = viewChild.required<ElementRef<HTMLElement>>('listbox');\n protected readonly end = viewChild.required<ElementRef<HTMLElement>>('end');\n\n /** The group being searched, on level 2. */\n protected readonly parent = computed(() => this.state()?.parent ?? null);\n\n protected readonly listLabel = computed(\n () => this.parent()?.title ?? this.state()?.label ?? this.label(),\n );\n\n /** The header template's context, while there is a group to head. */\n protected readonly headerContext = computed((): SuggestionMenuHeaderContext | null => {\n const group = this.parent();\n return group && { $implicit: group, back: this.back, backLabel: this.backLabel() };\n });\n\n /** The line under the list: failed, searching, loading more, nothing\n found, or nothing. Not \"searching\" over stale rows — dimmed, they say\n it themselves, and a line that came and went with every keystroke\n would resize the box (and have it placed again) twice per letter. */\n protected readonly status = computed(() => {\n const state = this.state();\n if (!state?.open) return '';\n if (state.error !== null) return this.errorLabel();\n if (state.loading) return state.stale ? '' : this.loadingLabel();\n if (state.loadingMore) return this.loadingMoreLabel();\n if (state.level === 2 && !state.items.length) return this.emptyLabel();\n return '';\n });\n\n /** What a screen reader should hear next: the status line, or how many\n rows the list has now. While the rows on screen answer the previous\n query there is no news yet — what was said last stands. */\n readonly #announcement = linkedSignal<\n { state: SuggestionMenuState | undefined; status: string; results: (count: number) => string },\n string\n >({\n source: () => ({ state: this.state(), status: this.status(), results: this.resultsLabel() }),\n computation: ({ state, status, results }, previous) => {\n if (!state?.open) return '';\n if (status) return status;\n if (state.loading) return previous?.value ?? '';\n return results(state.items.length);\n },\n });\n\n /** The announcement, once the typing has settled. */\n protected readonly announced = debounced(this.#announcement, (text) => {\n const delay = this.announceDelay();\n return text && delay > 0\n ? new Promise<void>((resolve) => setTimeout(resolve, delay))\n : undefined;\n });\n\n /** A page can be asked for right now: more exist and nothing is out. */\n readonly #canLoadMore = computed(() => {\n const state = this.state();\n return !!state?.open && state.hasMore && !state.loading && !state.loadingMore;\n });\n\n /** What the box's place depends on: where the session starts, and what\n decides its size (rows, header, status line, query). An arrow press\n changes none of it, so it measures nothing. */\n readonly #layout = computed(\n () => {\n const state = this.state();\n if (!state?.open || !state.range) return null;\n return {\n from: state.range.from,\n rows: state.items.length,\n level: state.level,\n query: state.query,\n status: this.status(),\n clientRect: state.clientRect,\n offset: this.offset(),\n };\n },\n {\n equal: (a, b) =>\n a === b ||\n (!!a &&\n !!b &&\n a.from === b.from &&\n a.rows === b.rows &&\n a.level === b.level &&\n a.query === b.query &&\n a.status === b.status &&\n a.offset === b.offset),\n },\n );\n\n /** What moves the highlight: the row it is on, and the list it is in — a\n level, a query. Null while closed. */\n readonly #highlight = computed(() => {\n const state = this.state();\n return state?.open ? `${state.level}:${state.query}:${state.activeIndex}` : null;\n });\n\n /** Watches the list's end marker: its coming within two rows of the\n listbox's bottom edge asks for the next page. An observer, not a scroll\n listener — it speaks only when the marker crosses in, so scrolling\n costs nothing. Made on first use: its root is the rendered listbox. */\n #endObserver: IntersectionObserver | undefined;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => this.#endObserver?.disconnect());\n\n // Watched only while a page can be loaded. Observing afresh reports the\n // marker's current state, so a page too short to fill the box (the\n // marker still in view once it lands) asks for the next one straight\n // away, and a list that scrolls waits for the scroll.\n afterRenderEffect({\n read: () => {\n if (typeof IntersectionObserver === 'undefined') return;\n const canLoad = this.#canLoadMore();\n // Any new list re-arms the watch, not only a longer one: a source\n // that answers at once never passes through `loading`, and its next\n // list can have as many rows as the last.\n this.#items();\n const end = this.end().nativeElement;\n this.#endObserver ??= new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) this.state()?.loadMore();\n },\n { root: this.listbox().nativeElement, rootMargin: '0px 0px 64px 0px' },\n );\n this.#endObserver.unobserve(end);\n if (canLoad) this.#endObserver.observe(end);\n },\n });\n\n // Placing the box: after its rows are rendered, measured in one phase and\n // written in the next — the plugin never touches the element, so no read\n // follows a write inside a keystroke. Shown only once it is in place.\n afterRenderEffect({\n earlyRead: () => {\n const layout = this.#layout();\n const anchor = layout?.clientRect();\n return layout && anchor ? measureMenuPlacement(anchor, this.#host, layout.offset) : null;\n },\n write: (placement) => {\n const place = placement();\n const style = this.#host.style;\n const visibility = place ? 'visible' : 'hidden';\n if (place) {\n const left = `${place.left}px`;\n const top = `${place.top}px`;\n if (style.left !== left) style.left = left;\n if (style.top !== top) style.top = top;\n }\n if (style.visibility !== visibility) style.visibility = visibility;\n },\n });\n\n // The highlighted row stays visible as the arrows walk past the fold —\n // one watch for the whole list, not one per row: measured in one phase,\n // scrolled in the next, the listbox only. A new query is a new list\n // (back at its top row); a page landing under a list scrolled by hand is\n // not, and must not pull it back.\n afterRenderEffect({\n earlyRead: () => {\n if (this.#highlight() === null) return null;\n const list = this.listbox().nativeElement;\n const row = list.querySelector<HTMLElement>('[data-active]');\n if (!row) return null;\n const { offsetTop: top, offsetHeight: height } = row;\n const { scrollTop, clientHeight } = list;\n if (top < scrollTop) return { list, scrollTop: top };\n if (top + height > scrollTop + clientHeight) {\n return { list, scrollTop: top + height - clientHeight };\n }\n return null;\n },\n write: (scroll) => {\n const target = scroll();\n if (target) target.list.scrollTop = target.scrollTop;\n },\n });\n\n // A level starts at its top: entering a group or leaving one does not\n // keep the other list's scroll position.\n afterRenderEffect({\n write: () => {\n this.parent();\n this.listbox().nativeElement.scrollTop = 0;\n },\n });\n }\n\n protected readonly back = (): void => this.state()?.back();\n}\n","@if (parent(); as group) {\n <div data-slot=\"header\">\n @if (header(); as slot) {\n <ng-container *ngTemplateOutlet=\"slot.template; context: headerContext()\" />\n } @else {\n <!-- The pointer's way back; the keyboard's is Backspace in the editor,\n which keeps the focus — so this never joins the tab order. -->\n <button\n type=\"button\"\n data-slot=\"back\"\n tabindex=\"-1\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\">\n <path d=\"M15.41 7.41 14 6l-6 6 6 6 1.41-1.41L10.83 12z\" />\n </svg>\n </button>\n <span data-slot=\"title\">{{ group.title }}</span>\n }\n </div>\n}\n\n<div\n #listbox\n role=\"listbox\"\n data-slot=\"listbox\"\n [attr.id]=\"state()?.listboxId\"\n [attr.aria-label]=\"listLabel()\"\n [attr.aria-busy]=\"state()?.loading || state()?.loadingMore || null\"\n [attr.data-stale]=\"state()?.stale || null\"\n>\n <ng-content />\n <!-- The end of the list, watched for the next page (never an option). -->\n <div #end data-slot=\"end\" role=\"none\" aria-hidden=\"true\"></div>\n</div>\n\n<!-- What is going on, for the eye: at once, collapsed while there is nothing\n to say. -->\n<div\n data-slot=\"status\"\n aria-hidden=\"true\"\n [attr.data-empty]=\"!status() || null\"\n [textContent]=\"status()\"\n></div>\n\n<!-- …and for a screen reader: settled, and with the result count. Always in\n the accessibility tree — visible while the box around it is hidden — so\n the first words of an opening menu are heard too. -->\n<div role=\"status\" data-slot=\"announcer\">{{ announced.value() }}</div>\n","import { Component, computed, inject, input } from '@angular/core';\nimport { SuggestionItem } from '@h-k-dev/angular-email-editor';\nimport { SuggestionMenu } from './suggestion-menu';\n\n/**\n * One row of a suggestion menu: an option of its listbox, standing for one of\n * the state's items. The host fills the row; the row takes its id (the one\n * the editor's `aria-activedescendant` names), reflects the highlight as\n * `aria-selected` and `data-active` — which is what the menu keeps scrolled\n * into view — and applies its item on click: a group opens, a command runs.\n *\n * Never focusable, never a button: the caret stays in the editor, and the\n * extension keeps a press on the menu from taking it away.\n */\n@Component({\n selector: '[email-suggestion-menu-item]',\n template: '<ng-content />',\n styleUrl: './suggestion-menu-item.scss',\n host: {\n role: 'option',\n '[attr.id]': 'id()',\n '[attr.aria-selected]': 'active()',\n '[attr.data-active]': 'active() || null',\n '[attr.data-group]': '!!item().children || null',\n '(click)': 'select()',\n },\n})\nexport class SuggestionMenuItem {\n /** The item this row stands for — one of the menu state's `items`. */\n readonly item = input.required<SuggestionItem>();\n\n readonly #menu = inject(SuggestionMenu);\n\n readonly #index = computed(() => this.#menu.indexOf(this.item()));\n\n /** The keyboard highlight is on this row. */\n readonly active = computed(() => {\n const index = this.#index();\n return index >= 0 && index === this.#menu.activeIndex();\n });\n\n protected readonly id = computed(() => {\n const optionId = this.#menu.optionId();\n const index = this.#index();\n return optionId && index >= 0 ? optionId(index) : null;\n });\n\n protected select(): void {\n this.#menu.state()?.select(this.item());\n }\n}\n","import { Component } from '@angular/core';\n\n/**\n * A heading in a suggestion menu's list: the words of a section\n * (`SuggestionItem.section`, worded by the state's `sectionTitle`), shown\n * where the section changes from one row to the next. Never an option: it\n * takes no highlight, no click, and no place in the count — presentation,\n * the way a chat's slash menu heads its groups.\n *\n * @for (item of state.items; track item.id) {\n * @if (item.section && item.section !== state.items[$index - 1]?.section) {\n * <div email-suggestion-menu-section>{{ state.sectionTitle(item.section) }}</div>\n * }\n * <div email-suggestion-menu-item [item]=\"item\">…</div>\n * }\n */\n@Component({\n selector: '[email-suggestion-menu-section]',\n template: '<ng-content />',\n styleUrl: './suggestion-menu-section.scss',\n host: { role: 'presentation' },\n})\nexport class SuggestionMenuSection {}\n","/*\n * Public API Surface of @h-k-dev/angular-email-editor/suggestion-menu\n */\n\nexport * from './suggestion-menu';\nexport * from './suggestion-menu-item';\nexport * from './suggestion-menu.slots';\nexport * from './suggestion-menu-section';\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-suggestion-menu.mjs","sources":["../../../projects/angular-email-editor/suggestion-menu/suggestion-menu.slots.ts","../../../projects/angular-email-editor/suggestion-menu/suggestion-menu.ts","../../../projects/angular-email-editor/suggestion-menu/suggestion-menu.html","../../../projects/angular-email-editor/suggestion-menu/suggestion-menu-item.ts","../../../projects/angular-email-editor/suggestion-menu/suggestion-menu-section.ts","../../../projects/angular-email-editor/suggestion-menu/public-api.ts","../../../projects/angular-email-editor/suggestion-menu/h-k-dev-angular-email-editor-suggestion-menu.ts"],"sourcesContent":["import { Directive, TemplateRef, inject } from '@angular/core';\nimport { SuggestionGroup } from '@h-k-dev/angular-email-editor';\n\n/**\n * A suggestion menu's header slot, shown on level 2 above the group's\n * children. The default is a back button and the group's title; a host\n * that wants its own — a Material icon button, the group's icon, a\n * breadcrumb — hands the menu a template:\n *\n * <div email-suggestion-menu [state]=\"state()\">\n * <ng-template emailSuggestionMenuHeader let-group let-back=\"back\" let-label=\"backLabel\">\n * <button mat-icon-button tabindex=\"-1\" [attr.aria-label]=\"label\" (click)=\"back()\">\n * <mat-icon>arrow_back</mat-icon>\n * </button>\n * {{ group.title }}\n * </ng-template>\n * …\n * </div>\n *\n * The template renders inside the menu's own `header` box.\n */\n\n/** What the header template is given. */\nexport interface SuggestionMenuHeaderContext {\n /** The group whose children are listed — its title already translated. */\n readonly $implicit: SuggestionGroup;\n /** Back to level 1 with an empty query. */\n readonly back: () => void;\n /** The back control's accessible name, as the menu was given it. */\n readonly backLabel: string;\n}\n\n/** Marks the `ng-template` the menu renders as its level-2 header. */\n@Directive({ selector: 'ng-template[emailSuggestionMenuHeader]' })\nexport class SuggestionMenuHeader {\n readonly template = inject<TemplateRef<SuggestionMenuHeaderContext>>(TemplateRef);\n\n static ngTemplateContextGuard(\n _directive: SuggestionMenuHeader,\n context: unknown,\n ): context is SuggestionMenuHeaderContext {\n return true;\n }\n}\n","import {\n Component,\n DestroyRef,\n ElementRef,\n inject,\n\n // Signals\n afterRenderEffect,\n computed,\n contentChild,\n debounced,\n input,\n linkedSignal,\n viewChild,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { SuggestionItem, SuggestionMenuState, measureMenuPlacement } from '@h-k-dev/angular-email-editor';\nimport { SuggestionMenuHeader, SuggestionMenuHeaderContext } from './suggestion-menu.slots';\n\n/**\n * A suggestion menu's floating box — the element `createSuggestionMenu` is\n * given, rendered from the state it reports. The extension does the work\n * (finding the trigger, filtering, paging, the keys, placing the box,\n * applying); this gives the state its roles and ids, so the editor's\n * `aria-controls` and `aria-activedescendant` land on real elements, keeps\n * the next page coming as the list scrolls, and says what is going on.\n *\n * **The pair.** The menu is the container; the host renders one\n * `[email-suggestion-menu-item]` per item into it and decides what a row\n * shows (an icon, the title, a detail). Rows are options of the menu's\n * listbox and never take focus: the caret stays in the editor, which is the\n * combobox. One pair serves every trigger — `/`, `{{`, `||` — at once: they\n * never open together, so a menu of several triggers is still one element\n * and one state, which says whose list it is (`trigger`, `label`).\n *\n * <div email-suggestion-menu #menu [state]=\"state()\">\n * @for (item of state()?.items; track item.id) {\n * <div email-suggestion-menu-item [item]=\"item\">{{ item.title }}</div>\n * }\n * </div>\n *\n * createSuggestionMenu({ element: menu, onChange: (s) => state.set(s), triggers: [\n * { trigger: '/', label: 'Insert block', items: extensionSuggestions },\n * { trigger: '{{', label: 'Tokens', source: fetchMergeTags },\n * ] })\n *\n * **Two levels.** Inside a group the menu shows a header above the list — a\n * back button and the group's title by default, or the host's\n * `ng-template[emailSuggestionMenuHeader]` — names the listbox after the\n * group, and says \"No results\" rather than closing when nothing matches.\n *\n * **Said twice, differently.** What is going on shows as a line under the\n * list, at once. A screen reader hears it from a separate live region that\n * waits for the typing to settle (`announceDelay`) and also counts the\n * results — the highlighted option's id does not change when the list is\n * filtered under it, so nothing else would say the list is a new one.\n *\n * Every word it says is an input, English by default.\n */\n@Component({\n selector: '[email-suggestion-menu]',\n imports: [NgTemplateOutlet],\n templateUrl: './suggestion-menu.html',\n styleUrl: './suggestion-menu.scss',\n host: {\n '[attr.data-level]': 'state()?.level ?? 1',\n },\n})\nexport class SuggestionMenu {\n /** The extension's latest state — undefined before the editor mounts. */\n readonly state = input<SuggestionMenuState>();\n\n /** Names the listbox on level 1 when the open trigger has no `label` of\n its own — a menu of several triggers names each list there (\"Insert\n block\", \"Personalization tokens\"); level 2 is named by its group. */\n readonly label = input('Suggestions');\n /** The level-2 back button's accessible name. */\n readonly backLabel = input('Back');\n /** Said while a source is still searching. */\n readonly loadingLabel = input('Searching…');\n /** Said on level 2 when nothing matches. */\n readonly emptyLabel = input('No results');\n /** Said while a further page is on its way. */\n readonly loadingMoreLabel = input('Loading more…');\n /** Said when the source's answer failed. */\n readonly errorLabel = input('Couldn’t load suggestions');\n /** Announced once a list is in: how many rows it has. */\n readonly resultsLabel = input<(count: number) => string>((count) =>\n count === 1 ? '1 result' : `${count} results`,\n );\n /** Milliseconds the announcement waits for the typing to settle, so a\n screen reader hears the list that stayed, not one per letter. Going\n quiet (the menu closes) never waits. 0 announces at once. */\n readonly announceDelay = input(400);\n /** Gap between the trigger's line and the menu, in px. */\n readonly offset = input(4);\n\n readonly #host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n\n /** The state's list. The extension reports a new state for every arrow\n press but the same list until it changes — so what hangs off the list\n (the index below, every row's position) sits an arrow press out. */\n readonly #items = computed(() => this.state()?.items);\n\n /** Each item's position in the list, looked up once per list — rows ask\n by identity, so a list of n rows costs n lookups, not n². */\n readonly #indices = computed(\n () => new Map(this.#items()?.map((item, index) => [item, index]) ?? []),\n );\n\n /** The keyboard-highlighted row's index; -1 before there is a state. */\n readonly activeIndex = computed(() => this.state()?.activeIndex ?? -1);\n\n /** The extension's id for the option at an index — the same function for\n the menu's whole life. */\n readonly optionId = computed(() => this.state()?.optionId);\n\n /** Where `item` sits in the current list; -1 when it is not in it. */\n indexOf(item: SuggestionItem): number {\n return this.#indices().get(item) ?? -1;\n }\n\n protected readonly header = contentChild(SuggestionMenuHeader);\n protected readonly listbox = viewChild.required<ElementRef<HTMLElement>>('listbox');\n protected readonly end = viewChild.required<ElementRef<HTMLElement>>('end');\n\n /** The group being searched, on level 2. */\n protected readonly parent = computed(() => this.state()?.parent ?? null);\n\n protected readonly listLabel = computed(\n () => this.parent()?.title ?? this.state()?.label ?? this.label(),\n );\n\n /** The header template's context, while there is a group to head. */\n protected readonly headerContext = computed((): SuggestionMenuHeaderContext | null => {\n const group = this.parent();\n return group && { $implicit: group, back: this.back, backLabel: this.backLabel() };\n });\n\n /** The line under the list: failed, searching, loading more, nothing\n found, or nothing. Not \"searching\" over stale rows — dimmed, they say\n it themselves, and a line that came and went with every keystroke\n would resize the box (and have it placed again) twice per letter. */\n protected readonly status = computed(() => {\n const state = this.state();\n if (!state?.open) return '';\n if (state.error !== null) return this.errorLabel();\n if (state.loading) return state.stale ? '' : this.loadingLabel();\n if (state.loadingMore) return this.loadingMoreLabel();\n if (state.level === 2 && !state.items.length) return this.emptyLabel();\n return '';\n });\n\n /** What a screen reader should hear next: the status line, or how many\n rows the list has now. While the rows on screen answer the previous\n query there is no news yet — what was said last stands. */\n readonly #announcement = linkedSignal<\n { state: SuggestionMenuState | undefined; status: string; results: (count: number) => string },\n string\n >({\n source: () => ({ state: this.state(), status: this.status(), results: this.resultsLabel() }),\n computation: ({ state, status, results }, previous) => {\n if (!state?.open) return '';\n if (status) return status;\n if (state.loading) return previous?.value ?? '';\n return results(state.items.length);\n },\n });\n\n /** The announcement, once the typing has settled. */\n protected readonly announced = debounced(this.#announcement, (text) => {\n const delay = this.announceDelay();\n return text && delay > 0\n ? new Promise<void>((resolve) => setTimeout(resolve, delay))\n : undefined;\n });\n\n /** A page can be asked for right now: more exist and nothing is out. */\n readonly #canLoadMore = computed(() => {\n const state = this.state();\n return !!state?.open && state.hasMore && !state.loading && !state.loadingMore;\n });\n\n /** What the box's place depends on: where the session starts, and what\n decides its size (rows, header, status line, query). An arrow press\n changes none of it, so it measures nothing. */\n readonly #layout = computed(\n () => {\n const state = this.state();\n if (!state?.open || !state.range) return null;\n return {\n from: state.range.from,\n rows: state.items.length,\n level: state.level,\n query: state.query,\n status: this.status(),\n clientRect: state.clientRect,\n offset: this.offset(),\n };\n },\n {\n equal: (a, b) =>\n a === b ||\n (!!a &&\n !!b &&\n a.from === b.from &&\n a.rows === b.rows &&\n a.level === b.level &&\n a.query === b.query &&\n a.status === b.status &&\n a.offset === b.offset),\n },\n );\n\n /** What moves the highlight: the row it is on, and the list it is in — a\n level, a query. Null while closed. */\n readonly #highlight = computed(() => {\n const state = this.state();\n return state?.open ? `${state.level}:${state.query}:${state.activeIndex}` : null;\n });\n\n /** Watches the list's end marker: its coming within two rows of the\n listbox's bottom edge asks for the next page. An observer, not a scroll\n listener — it speaks only when the marker crosses in, so scrolling\n costs nothing. Made on first use: its root is the rendered listbox. */\n #endObserver: IntersectionObserver | undefined;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => this.#endObserver?.disconnect());\n\n // Watched only while a page can be loaded. Observing afresh reports the\n // marker's current state, so a page too short to fill the box (the\n // marker still in view once it lands) asks for the next one straight\n // away, and a list that scrolls waits for the scroll.\n afterRenderEffect({\n read: () => {\n if (typeof IntersectionObserver === 'undefined') return;\n const canLoad = this.#canLoadMore();\n // Any new list re-arms the watch, not only a longer one: a source\n // that answers at once never passes through `loading`, and its next\n // list can have as many rows as the last.\n this.#items();\n const end = this.end().nativeElement;\n this.#endObserver ??= new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) this.state()?.loadMore();\n },\n { root: this.listbox().nativeElement, rootMargin: '0px 0px 64px 0px' },\n );\n this.#endObserver.unobserve(end);\n if (canLoad) this.#endObserver.observe(end);\n },\n });\n\n // Placing the box: after its rows are rendered, measured in one phase and\n // written in the next — the plugin never touches the element, so no read\n // follows a write inside a keystroke. Shown only once it is in place.\n //\n // A box that fits on neither side of the line is shrunk to the side with\n // more room. The cap goes on the listbox, not the box: the box keeps its\n // own max-height (the --email-suggestion-menu-max-height token) to be\n // read, and its height without the cap is its rendered height plus what\n // the capped list hides — a box measured at its last cap would choose its\n // side by the old room and flip back and forth.\n afterRenderEffect({\n earlyRead: () => {\n const layout = this.#layout();\n const anchor = layout?.clientRect();\n if (!layout || !anchor) return null;\n const list = this.listbox().nativeElement;\n const rendered = this.#host.offsetHeight;\n const cap = parseFloat(getComputedStyle(this.#host).maxHeight);\n const full = rendered + list.scrollHeight - list.clientHeight;\n const height = cap >= 0 ? Math.min(full, cap) : full;\n const place = measureMenuPlacement(anchor, this.#host, layout.offset, height);\n return place && { ...place, chrome: rendered - list.offsetHeight };\n },\n write: (placement) => {\n const place = placement();\n const style = this.#host.style;\n const visibility = place ? 'visible' : 'hidden';\n if (place) {\n const left = `${place.left}px`;\n const top = `${place.top}px`;\n const listHeight =\n place.maxHeight === null ? '' : `${Math.max(place.maxHeight - place.chrome, 0)}px`;\n const list = this.listbox().nativeElement.style;\n if (style.left !== left) style.left = left;\n if (style.top !== top) style.top = top;\n if (list.maxHeight !== listHeight) list.maxHeight = listHeight;\n }\n if (style.visibility !== visibility) style.visibility = visibility;\n },\n });\n\n // The highlighted row stays visible as the arrows walk past the fold —\n // one watch for the whole list, not one per row: measured in one phase,\n // scrolled in the next, the listbox only. A new query is a new list\n // (back at its top row); a page landing under a list scrolled by hand is\n // not, and must not pull it back.\n afterRenderEffect({\n earlyRead: () => {\n if (this.#highlight() === null) return null;\n const list = this.listbox().nativeElement;\n const row = list.querySelector<HTMLElement>('[data-active]');\n if (!row) return null;\n const { offsetTop: top, offsetHeight: height } = row;\n const { scrollTop, clientHeight } = list;\n if (top < scrollTop) return { list, scrollTop: top };\n if (top + height > scrollTop + clientHeight) {\n return { list, scrollTop: top + height - clientHeight };\n }\n return null;\n },\n write: (scroll) => {\n const target = scroll();\n if (target) target.list.scrollTop = target.scrollTop;\n },\n });\n\n // A level starts at its top: entering a group or leaving one does not\n // keep the other list's scroll position.\n afterRenderEffect({\n write: () => {\n this.parent();\n this.listbox().nativeElement.scrollTop = 0;\n },\n });\n }\n\n protected readonly back = (): void => this.state()?.back();\n}\n","@if (parent(); as group) {\n <div data-slot=\"header\">\n @if (header(); as slot) {\n <ng-container *ngTemplateOutlet=\"slot.template; context: headerContext()\" />\n } @else {\n <!-- The pointer's way back; the keyboard's is Backspace in the editor,\n which keeps the focus — so this never joins the tab order. -->\n <button\n type=\"button\"\n data-slot=\"back\"\n tabindex=\"-1\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\">\n <path d=\"M15.41 7.41 14 6l-6 6 6 6 1.41-1.41L10.83 12z\" />\n </svg>\n </button>\n <span data-slot=\"title\">{{ group.title }}</span>\n }\n </div>\n}\n\n<div\n #listbox\n role=\"listbox\"\n data-slot=\"listbox\"\n [attr.id]=\"state()?.listboxId\"\n [attr.aria-label]=\"listLabel()\"\n [attr.aria-busy]=\"state()?.loading || state()?.loadingMore || null\"\n [attr.data-stale]=\"state()?.stale || null\"\n>\n <ng-content />\n <!-- The end of the list, watched for the next page (never an option). -->\n <div #end data-slot=\"end\" role=\"none\" aria-hidden=\"true\"></div>\n</div>\n\n<!-- What is going on, for the eye: at once, collapsed while there is nothing\n to say. -->\n<div\n data-slot=\"status\"\n aria-hidden=\"true\"\n [attr.data-empty]=\"!status() || null\"\n [textContent]=\"status()\"\n></div>\n\n<!-- …and for a screen reader: settled, and with the result count. Always in\n the accessibility tree — visible while the box around it is hidden — so\n the first words of an opening menu are heard too. -->\n<div role=\"status\" data-slot=\"announcer\">{{ announced.value() }}</div>\n","import { Component, computed, inject, input } from '@angular/core';\nimport { SuggestionItem } from '@h-k-dev/angular-email-editor';\nimport { SuggestionMenu } from './suggestion-menu';\n\n/**\n * One row of a suggestion menu: an option of its listbox, standing for one of\n * the state's items. The host fills the row; the row takes its id (the one\n * the editor's `aria-activedescendant` names), reflects the highlight as\n * `aria-selected` and `data-active` — which is what the menu keeps scrolled\n * into view — and applies its item on click: a group opens, a command runs.\n *\n * Never focusable, never a button: the caret stays in the editor, and the\n * extension keeps a press on the menu from taking it away.\n */\n@Component({\n selector: '[email-suggestion-menu-item]',\n template: '<ng-content />',\n styleUrl: './suggestion-menu-item.scss',\n host: {\n role: 'option',\n '[attr.id]': 'id()',\n '[attr.aria-selected]': 'active()',\n '[attr.data-active]': 'active() || null',\n '[attr.data-group]': '!!item().children || null',\n '(click)': 'select()',\n },\n})\nexport class SuggestionMenuItem {\n /** The item this row stands for — one of the menu state's `items`. */\n readonly item = input.required<SuggestionItem>();\n\n readonly #menu = inject(SuggestionMenu);\n\n readonly #index = computed(() => this.#menu.indexOf(this.item()));\n\n /** The keyboard highlight is on this row. */\n readonly active = computed(() => {\n const index = this.#index();\n return index >= 0 && index === this.#menu.activeIndex();\n });\n\n protected readonly id = computed(() => {\n const optionId = this.#menu.optionId();\n const index = this.#index();\n return optionId && index >= 0 ? optionId(index) : null;\n });\n\n protected select(): void {\n this.#menu.state()?.select(this.item());\n }\n}\n","import { Component } from '@angular/core';\n\n/**\n * A heading in a suggestion menu's list: the words of a section\n * (`SuggestionItem.section`, worded by the state's `sectionTitle`), shown\n * where the section changes from one row to the next. Never an option: it\n * takes no highlight, no click, and no place in the count — presentation,\n * the way a chat's slash menu heads its groups.\n *\n * @for (item of state.items; track item.id) {\n * @if (item.section && item.section !== state.items[$index - 1]?.section) {\n * <div email-suggestion-menu-section>{{ state.sectionTitle(item.section) }}</div>\n * }\n * <div email-suggestion-menu-item [item]=\"item\">…</div>\n * }\n */\n@Component({\n selector: '[email-suggestion-menu-section]',\n template: '<ng-content />',\n styleUrl: './suggestion-menu-section.scss',\n host: { role: 'presentation' },\n})\nexport class SuggestionMenuSection {}\n","/*\n * Public API Surface of @h-k-dev/angular-email-editor/suggestion-menu\n */\n\nexport * from './suggestion-menu';\nexport * from './suggestion-menu-item';\nexport * from './suggestion-menu.slots';\nexport * from './suggestion-menu-section';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}