<commit_before>import React, { MutableRefObject, useEffect, useState, ReactNode, useMemo, useCallback, memo } from 'react';
import { c } from 'ttag';

import { useHandler, useModals } from '../../../hooks';
import { classnames } from '../../../helpers';

import Icon from '../../icon/Icon';

import InsertImageModal from '../modals/InsertImageModal';
import InsertLinkModal from '../modals/InsertLinkModal';
import { SquireType, LinkData } from '../squireConfig';
import {
    toggleBold,
    toggleItalic,
    makeLink,
    insertImage,
    getLinkAtCursor,
    toggleUnderline,
    toggleOrderedList,
    toggleUnorderedList,
    toggleBlockquote,
    listenToCursor,
    getPathInfo,
} from '../squireActions';
import SquireToolbarButton from './SquireToolbarButton';
import SquireToolbarSeparator from './SquireToolbarSeparator';
import SquireToolbarFontFaceDropdown from './SquireToolbarFontFaceDropdown';
import SquireToolbarFontSizeDropdown from './SquireToolbarFontSizeDropdown';
import SquireToolbarFontColorsDropdown from './SquireToolbarFontColorsDropdown';
import SquireToolbarAlignmentDropdown from './SquireToolbarAlignmentDropdown';
import SquireToolbarMoreDropdown from './SquireToolbarMoreDropdown';
import { ALIGNMENT, SquireEditorMetadata } from '../interface';

interface Props {
    metadata: SquireEditorMetadata;
    onChangeMetadata: (change: Partial<SquireEditorMetadata>) => void;
    isNarrow: boolean;
    squireRef: MutableRefObject<SquireType>;
    editorReady: boolean;
    onAddImages: (files: File[]) => void;
    moreDropdownExtension: ReactNode;
}

const SquireToolbar = ({
    metadata,
    onChangeMetadata,
    isNarrow,
    squireRef,
    editorReady,
    onAddImages,
    moreDropdownExtension,
}: Props) => {
    const [squireInfos, setSquireInfos] = useState<{ [test: string]: boolean }>({});

    const { createModal } = useModals();

    const handleCursor = useHandler(() => setSquireInfos(getPathInfo(squireRef.current)));
    const handleCursorDebounced = useHandler(handleCursor, { debounce: 500 });

    const forceRefresh = (action: () => void) => () => {
        action();
        handleCursor();
    };

    useEffect(() => {
        const removeListener = listenToCursor(squireRef.current, handleCursorDebounced);

        return () => {
            handleCursorDebounced.abort?.();
            removeListener?.();
        };
    }, [editorReady]);

    const handleBold = useCallback(<commit_msg>[MAILWEB-2253] Fix some leaking state update after unmounting<commit_after>import React, { MutableRefObject, useEffect, useState, ReactNode, useMemo, useCallback, memo } from 'react';
import { c } from 'ttag';
import { classnames } from '../../../helpers';
import { useHandler, useIsMounted, useModals } from '../../../hooks';
import Icon from '../../icon/Icon';
import InsertImageModal from '../modals/InsertImageModal';
import InsertLinkModal from '../modals/InsertLinkModal';
import { SquireType, LinkData } from '../squireConfig';
import {
    toggleBold,
    toggleItalic,
    makeLink,
    insertImage,
    getLinkAtCursor,
    toggleUnderline,
    toggleOrderedList,
    toggleUnorderedList,
    toggleBlockquote,
    listenToCursor,
    getPathInfo,
} from '../squireActions';
import SquireToolbarButton from './SquireToolbarButton';
import SquireToolbarSeparator from './SquireToolbarSeparator';
import SquireToolbarFontFaceDropdown from './SquireToolbarFontFaceDropdown';
import SquireToolbarFontSizeDropdown from './SquireToolbarFontSizeDropdown';
import SquireToolbarFontColorsDropdown from './SquireToolbarFontColorsDropdown';
import SquireToolbarAlignmentDropdown from './SquireToolbarAlignmentDropdown';
import SquireToolbarMoreDropdown from './SquireToolbarMoreDropdown';
import { ALIGNMENT, SquireEditorMetadata } from '../interface';

interface Props {
    metadata: SquireEditorMetadata;
    onChangeMetadata: (change: Partial<SquireEditorMetadata>) => void;
    isNarrow: boolean;
    squireRef: MutableRefObject<SquireType>;
    editorReady: boolean;
    onAddImages: (files: File[]) => void;
    moreDropdownExtension: ReactNode;
}

const SquireToolbar = ({
    metadata,
    onChangeMetadata,
    isNarrow,
    squireRef,
    editorReady,
    onAddImages,
    moreDropdownExtension,
}: Props) => {
    const isMounted = useIsMounted();
    const [squireInfos, setSquireInfos] = useState<{ [test: string]: boolean }>({});

    const { createModal } = useModals();

    const handleCursor = useHandler(() => {
        if (isMounted()) {
            setSquireInfos(getPathInfo(squireRef.current));
        }
    });
    const handleCursorDebounced = useHandler(handleCursor, { debounce: 500 });

    const forceRefresh = (action: () => void) => () => {
        action();
        handleCursor();
    };

    useEffect(() => {
        const removeListener = listenToCursor(squireRef.current, handleCursorDebounced);

        return () => {
            handleCursorDebounced.abort?.();
            removeListener?.();
        };
    }, [editorReady]);

    const handleBold = useCallback(
{'fraction_non_alphanumeric': 0.12126607319485658, 'fraction_numerical': 0.0019782393669634025, 'mean_word_length': 4.0308457711442784, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '137454', 'n_tokens_mistral': 1418, 'n_tokens_neox': 1447, 'n_words': 322}