bootstrap_typeahead: Fix compose typeahead overflowing when expanded.

When compose box is expanded, typeahead overlfows the top of the window.
We move the typeahead to the bottom of the screen and let
preventOverflow shift it into the visible area.
This commit is contained in:
Aman Agrawal
2024-05-07 15:15:50 +05:30
committed by Tim Abbott
parent 4e87f35c7d
commit d1050376e1
4 changed files with 56 additions and 21 deletions

View File

@@ -346,6 +346,27 @@ export class Typeahead<ItemType extends string | object> {
maxWidth: "none", maxWidth: "none",
theme: "popover-menu", theme: "popover-menu",
placement: this.dropup ? "top-start" : "bottom-start", placement: this.dropup ? "top-start" : "bottom-start",
popperOptions: {
modifiers: [
{
// This will only work if there is enough space on the fallback placement, otherwise
// `preventOverflow` will be used to position it in the visible space.
name: "flip",
options: {
fallbackPlacements: ["top-start", "bottom-start"],
},
},
{
name: "preventOverflow",
options: {
// This seems required to prevent overflow, maybe because our placements are
// not the usual top, bottom, left, right.
// https://popper.js.org/docs/v2/modifiers/prevent-overflow/#altaxis
altAxis: true,
},
},
],
},
interactive: true, interactive: true,
appendTo: () => document.body, appendTo: () => document.body,
showOnCreate: true, showOnCreate: true,

View File

@@ -10,6 +10,7 @@ import {
wrapFieldSelection, wrapFieldSelection,
} from "text-field-edit"; } from "text-field-edit";
import type {Typeahead} from "./bootstrap_typeahead";
import * as bulleted_numbered_list_util from "./bulleted_numbered_list_util"; import * as bulleted_numbered_list_util from "./bulleted_numbered_list_util";
import * as common from "./common"; import * as common from "./common";
import {$t} from "./i18n"; import {$t} from "./i18n";
@@ -58,8 +59,13 @@ type SelectedLinesSections = {
export let compose_spinner_visible = false; export let compose_spinner_visible = false;
export let shift_pressed = false; // true or false export let shift_pressed = false; // true or false
export let code_formatting_button_triggered = false; // true or false export let code_formatting_button_triggered = false; // true or false
export let compose_textarea_typeahead: Typeahead<object> | undefined;
let full_size_status = false; // true or false let full_size_status = false; // true or false
export function set_compose_textarea_typeahead(typeahead: Typeahead<object>): void {
compose_textarea_typeahead = typeahead;
}
export function set_code_formatting_button_triggered(value: boolean): void { export function set_code_formatting_button_triggered(value: boolean): void {
code_formatting_button_triggered = value; code_formatting_button_triggered = value;
} }
@@ -67,6 +73,10 @@ export function set_code_formatting_button_triggered(value: boolean): void {
// Some functions to handle the full size status explicitly // Some functions to handle the full size status explicitly
export function set_full_size(is_full: boolean): void { export function set_full_size(is_full: boolean): void {
full_size_status = is_full; full_size_status = is_full;
// Show typeahead at bottom of textarea on compose full size.
if (compose_textarea_typeahead) {
compose_textarea_typeahead.dropup = !is_full;
}
} }
export function is_full_size(): boolean { export function is_full_size(): boolean {

View File

@@ -1157,27 +1157,30 @@ export function initialize_compose_typeahead(selector) {
$element: $(selector), $element: $(selector),
type: "textarea", type: "textarea",
}; };
new Typeahead(bootstrap_typeahead_input, {
items: max_num_items, compose_ui.set_compose_textarea_typeahead(
dropup: true, new Typeahead(bootstrap_typeahead_input, {
// Performance note: We have trivial matcher/sorters to do items: max_num_items,
// matching and sorting inside the `source` field to avoid dropup: true,
// O(n) behavior in the number of users in the organization // Performance note: We have trivial matcher/sorters to do
// inside the typeahead library. // matching and sorting inside the `source` field to avoid
source: get_sorted_filtered_items, // O(n) behavior in the number of users in the organization
highlighter_html: content_highlighter_html, // inside the typeahead library.
matcher() { source: get_sorted_filtered_items,
return true; highlighter_html: content_highlighter_html,
}, matcher() {
sorter(items) { return true;
return items; },
}, sorter(items) {
updater: content_typeahead_selected, return items;
stopAdvance: true, // Do not advance to the next field on a Tab or Enter },
automated: compose_automated_selection, updater: content_typeahead_selected,
trigger_selection: compose_trigger_selection, stopAdvance: true, // Do not advance to the next field on a Tab or Enter
header_html: get_header_html, automated: compose_automated_selection,
}); trigger_selection: compose_trigger_selection,
header_html: get_header_html,
}),
);
} }
export function initialize({on_enter_send}) { export function initialize({on_enter_send}) {

View File

@@ -17,6 +17,7 @@ const compose_ui = mock_esm("../src/compose_ui", {
}, },
cursor_inside_code_block: () => false, cursor_inside_code_block: () => false,
set_code_formatting_button_triggered: noop, set_code_formatting_button_triggered: noop,
set_compose_textarea_typeahead: noop,
}); });
const compose_validate = mock_esm("../src/compose_validate", { const compose_validate = mock_esm("../src/compose_validate", {
validate_message_length: () => true, validate_message_length: () => true,