mirror of https://github.com/zulip/zulip.git
ts: Migrate `popover_menus` to typescript.
This commit migrates `popover_menus` module to TypeScript. Also adds a placeholder types declaration file for `css_variables` module.
This commit is contained in:
parent
bfff48decc
commit
02257b8cbf
|
@ -84,6 +84,7 @@ EXEMPT_FILES = make_set(
|
||||||
"web/src/copied_tooltip.ts",
|
"web/src/copied_tooltip.ts",
|
||||||
"web/src/copy_and_paste.js",
|
"web/src/copy_and_paste.js",
|
||||||
"web/src/csrf.ts",
|
"web/src/csrf.ts",
|
||||||
|
"web/src/css_variables.d.ts",
|
||||||
"web/src/css_variables.js",
|
"web/src/css_variables.js",
|
||||||
"web/src/custom_profile_fields_ui.js",
|
"web/src/custom_profile_fields_ui.js",
|
||||||
"web/src/dark_theme.ts",
|
"web/src/dark_theme.ts",
|
||||||
|
@ -166,9 +167,10 @@ EXEMPT_FILES = make_set(
|
||||||
"web/src/pm_list_dom.ts",
|
"web/src/pm_list_dom.ts",
|
||||||
"web/src/poll_modal.js",
|
"web/src/poll_modal.js",
|
||||||
"web/src/poll_widget.ts",
|
"web/src/poll_widget.ts",
|
||||||
"web/src/popover_menus.js",
|
"web/src/popover_menus.ts",
|
||||||
"web/src/popover_menus_data.js",
|
"web/src/popover_menus_data.js",
|
||||||
"web/src/popovers.ts",
|
"web/src/popovers.ts",
|
||||||
|
"web/src/popperjs.d.ts",
|
||||||
"web/src/read_receipts.js",
|
"web/src/read_receipts.js",
|
||||||
"web/src/ready.ts",
|
"web/src/ready.ts",
|
||||||
"web/src/realm_icon.ts",
|
"web/src/realm_icon.ts",
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
/* This is a placeholder typescript declaration file for `css_variables` module.
|
||||||
|
We can't convert the `css_variables` module to typescript yet because converting
|
||||||
|
it causes Webpack to trigger type checking with the TypeScript compiler, which is very expensive.
|
||||||
|
|
||||||
|
TS-migration of this module was reverted in this PR: https://github.com/zulip/zulip/pull/24985.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare const css_variables: {
|
||||||
|
media_breakpoints: {
|
||||||
|
xs_min: string;
|
||||||
|
sm_min: string;
|
||||||
|
md_min: string;
|
||||||
|
mc_min: string;
|
||||||
|
lg_min: string;
|
||||||
|
xl_min: string;
|
||||||
|
ml_min: string;
|
||||||
|
mm_min: string;
|
||||||
|
ms_min: string;
|
||||||
|
};
|
||||||
|
media_breakpoints_num: {
|
||||||
|
xs: number;
|
||||||
|
sm: number;
|
||||||
|
md: number;
|
||||||
|
mc: number;
|
||||||
|
lg: number;
|
||||||
|
xl: number;
|
||||||
|
ml: number;
|
||||||
|
mm: number;
|
||||||
|
ms: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export = css_variables;
|
|
@ -3,6 +3,7 @@
|
||||||
popovers system in popovers.js. */
|
popovers system in popovers.js. */
|
||||||
|
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
|
import type {Instance as PopoverInstance, Props as PopoverProps, ReferenceElement} from "tippy.js";
|
||||||
import tippy from "tippy.js";
|
import tippy from "tippy.js";
|
||||||
|
|
||||||
import * as blueslip from "./blueslip";
|
import * as blueslip from "./blueslip";
|
||||||
|
@ -12,7 +13,25 @@ import * as overlays from "./overlays";
|
||||||
import * as popovers from "./popovers";
|
import * as popovers from "./popovers";
|
||||||
import * as util from "./util";
|
import * as util from "./util";
|
||||||
|
|
||||||
export const popover_instances = {
|
type PopoverName =
|
||||||
|
| "compose_control_buttons"
|
||||||
|
| "starred_messages"
|
||||||
|
| "drafts"
|
||||||
|
| "left_sidebar_inbox_popover"
|
||||||
|
| "left_sidebar_all_messages_popover"
|
||||||
|
| "left_sidebar_recent_view_popover"
|
||||||
|
| "top_left_sidebar"
|
||||||
|
| "message_actions"
|
||||||
|
| "stream_settings"
|
||||||
|
| "compose_mobile_button"
|
||||||
|
| "topics_menu"
|
||||||
|
| "send_later"
|
||||||
|
| "change_visibility_policy"
|
||||||
|
| "personal_menu"
|
||||||
|
| "gear_menu"
|
||||||
|
| "help_menu";
|
||||||
|
|
||||||
|
export const popover_instances: Record<PopoverName, PopoverInstance | null> = {
|
||||||
compose_control_buttons: null,
|
compose_control_buttons: null,
|
||||||
starred_messages: null,
|
starred_messages: null,
|
||||||
drafts: null,
|
drafts: null,
|
||||||
|
@ -32,7 +51,7 @@ export const popover_instances = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Keyboard UI functions */
|
/* Keyboard UI functions */
|
||||||
export function popover_items_handle_keyboard(key, $items) {
|
export function popover_items_handle_keyboard(key: string, $items?: JQuery): void {
|
||||||
if (!$items) {
|
if (!$items) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -58,7 +77,7 @@ export function popover_items_handle_keyboard(key, $items) {
|
||||||
$items.eq(index).trigger("focus");
|
$items.eq(index).trigger("focus");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function focus_first_popover_item($items, index = 0) {
|
export function focus_first_popover_item($items: JQuery, index = 0): void {
|
||||||
if (!$items) {
|
if (!$items) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -66,56 +85,59 @@ export function focus_first_popover_item($items, index = 0) {
|
||||||
$items.eq(index).expectOne().trigger("focus");
|
$items.eq(index).expectOne().trigger("focus");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sidebar_menu_instance_handle_keyboard(instance, key) {
|
export function sidebar_menu_instance_handle_keyboard(
|
||||||
|
instance: PopoverInstance,
|
||||||
|
key: string,
|
||||||
|
): void {
|
||||||
const items = get_popover_items_for_instance(instance);
|
const items = get_popover_items_for_instance(instance);
|
||||||
popover_items_handle_keyboard(key, items);
|
popover_items_handle_keyboard(key, items);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get_visible_instance() {
|
export function get_visible_instance(): PopoverInstance | null | undefined {
|
||||||
return Object.values(popover_instances).find(Boolean);
|
return Object.values(popover_instances).find(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get_topic_menu_popover() {
|
export function get_topic_menu_popover(): PopoverInstance | null {
|
||||||
return popover_instances.topics_menu;
|
return popover_instances.topics_menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get_scheduled_messages_popover() {
|
export function get_scheduled_messages_popover(): PopoverInstance | null {
|
||||||
return popover_instances.send_later;
|
return popover_instances.send_later;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function is_scheduled_messages_popover_displayed() {
|
export function is_scheduled_messages_popover_displayed(): boolean | undefined {
|
||||||
return popover_instances.send_later?.state.isVisible;
|
return popover_instances.send_later?.state.isVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get_compose_control_buttons_popover() {
|
export function get_compose_control_buttons_popover(): PopoverInstance | null {
|
||||||
return popover_instances.compose_control_buttons;
|
return popover_instances.compose_control_buttons;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get_starred_messages_popover() {
|
export function get_starred_messages_popover(): PopoverInstance | null {
|
||||||
return popover_instances.starred_messages;
|
return popover_instances.starred_messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function is_personal_menu_popover_displayed() {
|
export function is_personal_menu_popover_displayed(): boolean | undefined {
|
||||||
return popover_instances.personal_menu?.state.isVisible;
|
return popover_instances.personal_menu?.state.isVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function is_gear_menu_popover_displayed() {
|
export function is_gear_menu_popover_displayed(): boolean | undefined {
|
||||||
return popover_instances.gear_menu?.state.isVisible;
|
return popover_instances.gear_menu?.state.isVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get_gear_menu_instance() {
|
export function get_gear_menu_instance(): PopoverInstance | null {
|
||||||
return popover_instances.gear_menu;
|
return popover_instances.gear_menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function is_help_menu_popover_displayed() {
|
export function is_help_menu_popover_displayed(): boolean | undefined {
|
||||||
return popover_instances.help_menu?.state.isVisible;
|
return popover_instances.help_menu?.state.isVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function is_message_actions_popover_displayed() {
|
export function is_message_actions_popover_displayed(): boolean | undefined {
|
||||||
return popover_instances.message_actions?.state.isVisible;
|
return popover_instances.message_actions?.state.isVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_popover_items_for_instance(instance) {
|
function get_popover_items_for_instance(instance: PopoverInstance): JQuery | undefined {
|
||||||
const $current_elem = $(instance.popper);
|
const $current_elem = $(instance.popper);
|
||||||
const class_name = $current_elem.attr("class");
|
const class_name = $current_elem.attr("class");
|
||||||
|
|
||||||
|
@ -127,7 +149,7 @@ function get_popover_items_for_instance(instance) {
|
||||||
return $current_elem.find("a:visible");
|
return $current_elem.find("a:visible");
|
||||||
}
|
}
|
||||||
|
|
||||||
export const default_popover_props = {
|
export const default_popover_props: Partial<PopoverProps> = {
|
||||||
delay: 0,
|
delay: 0,
|
||||||
appendTo: () => document.body,
|
appendTo: () => document.body,
|
||||||
trigger: "click",
|
trigger: "click",
|
||||||
|
@ -154,7 +176,8 @@ export const default_popover_props = {
|
||||||
phase: "beforeWrite",
|
phase: "beforeWrite",
|
||||||
requires: ["$$tippy"],
|
requires: ["$$tippy"],
|
||||||
fn({state}) {
|
fn({state}) {
|
||||||
const instance = state.elements.reference._tippy;
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
|
const instance = (state.elements.reference as ReferenceElement)._tippy!;
|
||||||
const $popover = $(state.elements.popper);
|
const $popover = $(state.elements.popper);
|
||||||
const $tippy_box = $popover.find(".tippy-box");
|
const $tippy_box = $popover.find(".tippy-box");
|
||||||
if ($tippy_box.hasClass("show-when-reference-hidden")) {
|
if ($tippy_box.hasClass("show-when-reference-hidden")) {
|
||||||
|
@ -249,7 +272,7 @@ export const left_sidebar_tippy_options = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export function on_show_prep(instance) {
|
export function on_show_prep(instance: PopoverInstance): void {
|
||||||
$(instance.popper).on("click", (e) => {
|
$(instance.popper).on("click", (e) => {
|
||||||
// Popover is not hidden on click inside it unless the click handler for the
|
// Popover is not hidden on click inside it unless the click handler for the
|
||||||
// element explicitly hides the popover when handling the event.
|
// element explicitly hides the popover when handling the event.
|
||||||
|
@ -264,22 +287,19 @@ export function on_show_prep(instance) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_props_for_popover_centering(popover_props) {
|
function get_props_for_popover_centering(
|
||||||
|
popover_props: Partial<PopoverProps>,
|
||||||
|
): Partial<PopoverProps> {
|
||||||
return {
|
return {
|
||||||
arrow: false,
|
arrow: false,
|
||||||
getReferenceClientRect: () => ({
|
getReferenceClientRect: () => new DOMRect(0, 0, 0, 0),
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
left: 0,
|
|
||||||
top: 0,
|
|
||||||
}),
|
|
||||||
placement: "top",
|
placement: "top",
|
||||||
popperOptions: {
|
popperOptions: {
|
||||||
modifiers: [
|
modifiers: [
|
||||||
{
|
{
|
||||||
name: "offset",
|
name: "offset",
|
||||||
options: {
|
options: {
|
||||||
offset({popper}) {
|
offset({popper}: {popper: DOMRect}) {
|
||||||
// Calculate the offset needed to place the reference in the center
|
// Calculate the offset needed to place the reference in the center
|
||||||
const x_offset_to_center = window.innerWidth / 2;
|
const x_offset_to_center = window.innerWidth / 2;
|
||||||
let y_offset_to_center = window.innerHeight / 2 - popper.height / 2;
|
let y_offset_to_center = window.innerHeight / 2 - popper.height / 2;
|
||||||
|
@ -291,7 +311,7 @@ function get_props_for_popover_centering(popover_props) {
|
||||||
// is causing a resize (thus calling this `offset` modifier function), in which case
|
// is causing a resize (thus calling this `offset` modifier function), in which case
|
||||||
// we need to move the popover to the top of the screen.
|
// we need to move the popover to the top of the screen.
|
||||||
if (util.is_mobile()) {
|
if (util.is_mobile()) {
|
||||||
const $focused_element = $(document.activeElement);
|
const $focused_element = $(document.activeElement!);
|
||||||
if (
|
if (
|
||||||
$focused_element.is(
|
$focused_element.is(
|
||||||
"input[type=text], input[type=number], textarea",
|
"input[type=text], input[type=number], textarea",
|
||||||
|
@ -334,7 +354,11 @@ function get_props_for_popover_centering(popover_props) {
|
||||||
|
|
||||||
// Toggles a popover menu directly; intended for use in keyboard
|
// Toggles a popover menu directly; intended for use in keyboard
|
||||||
// shortcuts and similar alternative ways to open a popover menu.
|
// shortcuts and similar alternative ways to open a popover menu.
|
||||||
export function toggle_popover_menu(target, popover_props, options) {
|
export function toggle_popover_menu(
|
||||||
|
target: ReferenceElement,
|
||||||
|
popover_props: Partial<PopoverProps>,
|
||||||
|
options?: {show_as_overlay_on_mobile: boolean},
|
||||||
|
): void {
|
||||||
const instance = target._tippy;
|
const instance = target._tippy;
|
||||||
if (instance) {
|
if (instance) {
|
||||||
instance.hide();
|
instance.hide();
|
||||||
|
@ -353,7 +377,7 @@ export function toggle_popover_menu(target, popover_props, options) {
|
||||||
|
|
||||||
if (popover_props.popperOptions?.modifiers) {
|
if (popover_props.popperOptions?.modifiers) {
|
||||||
popover_props.popperOptions.modifiers = [
|
popover_props.popperOptions.modifiers = [
|
||||||
...default_popover_props.popperOptions.modifiers,
|
...default_popover_props.popperOptions!.modifiers!,
|
||||||
...popover_props.popperOptions.modifiers,
|
...popover_props.popperOptions.modifiers,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -368,7 +392,7 @@ export function toggle_popover_menu(target, popover_props, options) {
|
||||||
|
|
||||||
// Main function to define a popover menu, opened via clicking on the
|
// Main function to define a popover menu, opened via clicking on the
|
||||||
// target selector.
|
// target selector.
|
||||||
export function register_popover_menu(target, popover_props) {
|
export function register_popover_menu(target: string, popover_props: Partial<PopoverProps>): void {
|
||||||
// For some elements, such as the click target to open the message
|
// For some elements, such as the click target to open the message
|
||||||
// actions menu, we want to avoid propagating the click event to
|
// actions menu, we want to avoid propagating the click event to
|
||||||
// parent elements. Tippy's built-in `delegate` method does not
|
// parent elements. Tippy's built-in `delegate` method does not
|
||||||
|
@ -389,7 +413,7 @@ export function register_popover_menu(target, popover_props) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initialize() {
|
export function initialize(): void {
|
||||||
/* Configure popovers to hide when toggling overlays. */
|
/* Configure popovers to hide when toggling overlays. */
|
||||||
overlays.register_pre_open_hook(popovers.hide_all);
|
overlays.register_pre_open_hook(popovers.hide_all);
|
||||||
overlays.register_pre_close_hook(popovers.hide_all);
|
overlays.register_pre_close_hook(popovers.hide_all);
|
Loading…
Reference in New Issue