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",
theme: "popover-menu",
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,
appendTo: () => document.body,
showOnCreate: true,

View File

@ -10,6 +10,7 @@ import {
wrapFieldSelection,
} from "text-field-edit";
import type {Typeahead} from "./bootstrap_typeahead";
import * as bulleted_numbered_list_util from "./bulleted_numbered_list_util";
import * as common from "./common";
import {$t} from "./i18n";
@ -58,8 +59,13 @@ type SelectedLinesSections = {
export let compose_spinner_visible = false;
export let shift_pressed = 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
export function set_compose_textarea_typeahead(typeahead: Typeahead<object>): void {
compose_textarea_typeahead = typeahead;
}
export function set_code_formatting_button_triggered(value: boolean): void {
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
export function set_full_size(is_full: boolean): void {
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 {

View File

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