mirror of
https://github.com/suitenumerique/docs.git
synced 2026-09-22 09:35:08 +02:00
🐛(frontend) prevent toasts from remounting components
useToastProvider()'s `toast` function is recreated by the provider every time any toast is shown anywhere in the app. useUploadFile listed it as a dependency of `uploadFile`, which is itself a dependency of useCreateBlockNote, so an unrelated toast (e.g. "Link copied!") recreated `uploadFile` and made BlockNote rebuild the whole editor instance, resetting the scroll position to the top of the document. Added useToast, a drop-in wrapper around useToastProvider that keeps `toast`'s identity stable behind a ref, and switched every call site in the app to use it instead of the provider's hook directly.
This commit is contained in:
+4
-7
@@ -5,17 +5,14 @@ import {
|
||||
useComponentsContext,
|
||||
useSelectedBlocks,
|
||||
} from '@blocknote/react';
|
||||
import {
|
||||
Loader,
|
||||
VariantType,
|
||||
useToastProvider,
|
||||
} from '@gouvfr-lasuite/ui-components';
|
||||
import { Loader, VariantType } from '@gouvfr-lasuite/ui-components';
|
||||
import { PropsWithChildren, ReactNode, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { isAPIError } from '@/api';
|
||||
import { Box, Icon } from '@/components';
|
||||
import { useDocOptions, useDocStore } from '@/docs/doc-management/';
|
||||
import { useToast } from '@/hooks';
|
||||
|
||||
import {
|
||||
AITransformActions,
|
||||
@@ -312,7 +309,7 @@ const AIMenuItem = ({
|
||||
icon,
|
||||
}: PropsWithChildren<AIMenuItemProps>) => {
|
||||
const Components = useComponentsContext();
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const editor = useBlockNoteEditor();
|
||||
@@ -357,7 +354,7 @@ const AIMenuItem = ({
|
||||
};
|
||||
|
||||
const useHandleAIError = () => {
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (error: unknown) => {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Block } from '@blocknote/core';
|
||||
import { VariantType, useToastProvider } from '@gouvfr-lasuite/ui-components';
|
||||
import { VariantType } from '@gouvfr-lasuite/ui-components';
|
||||
import { captureException } from '@sentry/nextjs';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { backendUrl } from '@/api';
|
||||
import { useConfig } from '@/core';
|
||||
import { useToast } from '@/hooks';
|
||||
import { formatFileSize } from '@/utils';
|
||||
import { isSafeUrl } from '@/utils/url';
|
||||
|
||||
@@ -17,7 +18,7 @@ const DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024; // Default to 10MB
|
||||
|
||||
export const useUploadFile = (docId: string) => {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const { data: config } = useConfig();
|
||||
const {
|
||||
mutateAsync: createDocAttachment,
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
ModalSize,
|
||||
Select,
|
||||
VariantType,
|
||||
useToastProvider,
|
||||
} from '@gouvfr-lasuite/ui-components';
|
||||
import i18next from 'i18next';
|
||||
import JSZip from 'jszip';
|
||||
@@ -17,6 +16,7 @@ import { Box, ButtonCloseModal, Text } from '@/components';
|
||||
import { useMediaUrl } from '@/core';
|
||||
import { useEditorStore } from '@/docs/doc-editor/stores/useEditorStore';
|
||||
import { type Doc, useTrans } from '@/docs/doc-management';
|
||||
import { useToast } from '@/hooks';
|
||||
import { fallbackLng } from '@/i18n/config';
|
||||
|
||||
import ModulesExport from '../hooks/';
|
||||
@@ -36,7 +36,7 @@ interface ModalExportProps {
|
||||
|
||||
export const ModalExport = ({ onClose, doc }: ModalExportProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const { editor } = useEditorStore();
|
||||
const [isExporting, setIsExporting] = useState(false);
|
||||
const { untitledDocument } = useTrans();
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
Button,
|
||||
VariantType,
|
||||
useToastProvider,
|
||||
} from '@gouvfr-lasuite/ui-components';
|
||||
import { Button, VariantType } from '@gouvfr-lasuite/ui-components';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Box, Card, Icon } from '@/components';
|
||||
@@ -16,10 +12,11 @@ import {
|
||||
} from '@/docs/doc-management';
|
||||
import { KEY_DOC_TREE } from '@/docs/doc-tree';
|
||||
import { KEY_LIST_DOC_TRASHBIN } from '@/docs/docs-grid';
|
||||
import { useToast } from '@/hooks';
|
||||
|
||||
export const AlertRestore = ({ doc }: { doc: Doc }) => {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
const { mutate: restoreDoc, error } = useRestoreDoc({
|
||||
listInvalidQueries: [
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { VariantType, useToastProvider } from '@gouvfr-lasuite/ui-components';
|
||||
import { VariantType } from '@gouvfr-lasuite/ui-components';
|
||||
import {
|
||||
UseMutationOptions,
|
||||
useMutation,
|
||||
@@ -9,6 +9,7 @@ import * as Y from 'yjs';
|
||||
|
||||
import { APIError, errorCauses, fetchAPI } from '@/api';
|
||||
import { KEY_LIST_DOC_VERSIONS } from '@/docs/doc-versioning/api/useDocVersions';
|
||||
import { useToast } from '@/hooks';
|
||||
import { toBase64 } from '@/utils/string';
|
||||
|
||||
import { useProviderStore } from '../stores';
|
||||
@@ -55,7 +56,7 @@ type DuplicateDocOptions = UseMutationOptions<
|
||||
|
||||
export function useDuplicateDoc(options?: DuplicateDocOptions) {
|
||||
const queryClient = useQueryClient();
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const { t } = useTranslation();
|
||||
const { provider } = useProviderStore();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { VariantType, useToastProvider } from '@gouvfr-lasuite/ui-components';
|
||||
import { VariantType } from '@gouvfr-lasuite/ui-components';
|
||||
import {
|
||||
UseMutationOptions,
|
||||
useMutation,
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
errorCauses,
|
||||
fetchAPI,
|
||||
} from '@/api';
|
||||
import { useToast } from '@/hooks';
|
||||
|
||||
import { Doc } from '../types';
|
||||
|
||||
@@ -71,7 +72,7 @@ export const importDoc = async ([file, mimeType]: [
|
||||
type UseImportDocOptions = UseMutationOptions<Doc, APIError, [File, string]>;
|
||||
|
||||
export function useImportDoc(props?: UseImportDocOptions) {
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const queryClient = useQueryClient();
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
||||
+2
-2
@@ -5,7 +5,6 @@ import {
|
||||
TreeViewMoveModeEnum,
|
||||
VariantType,
|
||||
useModal,
|
||||
useToastProvider,
|
||||
} from '@gouvfr-lasuite/ui-components';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { useState } from 'react';
|
||||
@@ -21,6 +20,7 @@ import {
|
||||
DocsGridItemDate,
|
||||
DocsGridItemTitle,
|
||||
} from '@/docs/docs-grid/components/DocsGridItem';
|
||||
import { useToast } from '@/hooks';
|
||||
import { useResponsiveStore } from '@/stores';
|
||||
|
||||
const AlertModalRequestAccess = dynamic(
|
||||
@@ -106,7 +106,7 @@ export const DocMoveModal = ({
|
||||
const { isDesktop, isTablet, isMobile } = useResponsiveStore();
|
||||
const isModal = (isDesktop || isTablet) && !isMobile;
|
||||
const handleInputSearch = useDebouncedCallback(setSearch, 700);
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
|
||||
const handleSelect = (docSelected: Doc) => {
|
||||
setDocSelected(docSelected);
|
||||
|
||||
+2
-3
@@ -4,7 +4,6 @@ import {
|
||||
Modal,
|
||||
ModalSize,
|
||||
VariantType,
|
||||
useToastProvider,
|
||||
} from '@gouvfr-lasuite/ui-components';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
@@ -12,7 +11,7 @@ import { Trans, useTranslation } from 'react-i18next';
|
||||
import { Box, ButtonCloseModal, Text, TextErrors } from '@/components';
|
||||
import { useConfig } from '@/core';
|
||||
import { KEY_LIST_DOC_TRASHBIN } from '@/docs/docs-grid';
|
||||
import { useKeyboardAction } from '@/hooks';
|
||||
import { useKeyboardAction, useToast } from '@/hooks';
|
||||
|
||||
import { KEY_DOC, KEY_LIST_FAVORITE_DOC } from '../api';
|
||||
import { KEY_LIST_DOC } from '../api/useDocs';
|
||||
@@ -31,7 +30,7 @@ export const ModalRemoveDoc = ({
|
||||
onClose,
|
||||
onSuccess,
|
||||
}: ModalRemoveDocProps) => {
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const { t } = useTranslation();
|
||||
const { data: config } = useConfig();
|
||||
const trashBinCutoffDays = config?.TRASHBIN_CUTOFF_DAYS || 30;
|
||||
|
||||
+3
-2
@@ -1,11 +1,12 @@
|
||||
import { VariantType, useToastProvider } from '@gouvfr-lasuite/ui-components';
|
||||
import { VariantType } from '@gouvfr-lasuite/ui-components';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useEditorStore } from '@/docs/doc-editor/stores/useEditorStore';
|
||||
import { useToast } from '@/hooks';
|
||||
|
||||
export const useCopyCurrentEditorToClipboard = () => {
|
||||
const { editor } = useEditorStore();
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return async (asFormat: 'html' | 'markdown') => {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { VariantType, useToastProvider } from '@gouvfr-lasuite/ui-components';
|
||||
import { VariantType } from '@gouvfr-lasuite/ui-components';
|
||||
import { t } from 'i18next';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useDropzone } from 'react-dropzone';
|
||||
|
||||
import { useConfig } from '@/core';
|
||||
import { useToast } from '@/hooks';
|
||||
import { formatFileSize } from '@/utils';
|
||||
|
||||
import { ContentTypes, useImportDoc } from '../api/useImportDoc';
|
||||
@@ -19,7 +20,7 @@ interface AcceptedMap {
|
||||
}
|
||||
|
||||
export const useImport = ({ onDragOver, onImportSuccess }: UseImportProps) => {
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const { data: config } = useConfig();
|
||||
|
||||
const MAX_FILE_SIZE = useMemo(() => {
|
||||
|
||||
+3
-6
@@ -1,13 +1,10 @@
|
||||
import {
|
||||
Button,
|
||||
VariantType,
|
||||
useToastProvider,
|
||||
} from '@gouvfr-lasuite/ui-components';
|
||||
import { Button, VariantType } from '@gouvfr-lasuite/ui-components';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Box, Card, Text } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { Doc, KEY_DOC, KEY_LIST_DOC } from '@/docs/doc-management';
|
||||
import { useToast } from '@/hooks';
|
||||
|
||||
import { useUpdateDocLink } from '../api/useUpdateDocLink';
|
||||
|
||||
@@ -21,7 +18,7 @@ interface DocDesynchronizedProps {
|
||||
export const DocDesynchronized = ({ doc }: DocDesynchronizedProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
|
||||
const { mutate: updateDocLink } = useUpdateDocLink({
|
||||
listInvalidQueries: [KEY_LIST_DOC, KEY_DOC],
|
||||
|
||||
+3
-2
@@ -1,10 +1,11 @@
|
||||
import { VariantType, useToastProvider } from '@gouvfr-lasuite/ui-components';
|
||||
import { VariantType } from '@gouvfr-lasuite/ui-components';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { css } from 'styled-components';
|
||||
|
||||
import { DropdownMenu, DropdownMenuOption, Text } from '@/components';
|
||||
import { Access, Doc, Role, useTrans } from '@/docs/doc-management/';
|
||||
import { useToast } from '@/hooks';
|
||||
|
||||
import { useDeleteDocAccess, useDeleteDocInvitation } from '../api';
|
||||
import { Invitation, isInvitation } from '../types';
|
||||
@@ -34,7 +35,7 @@ export const DocRoleDropdown = ({
|
||||
}: DocRoleDropdownProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { transRole, translatedRoles } = useTrans();
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
|
||||
const { mutate: removeDocInvitation } = useDeleteDocInvitation({
|
||||
onError: (error) => {
|
||||
|
||||
+3
-3
@@ -2,7 +2,6 @@ import {
|
||||
Button,
|
||||
ButtonProps,
|
||||
VariantType,
|
||||
useToastProvider,
|
||||
} from '@gouvfr-lasuite/ui-components';
|
||||
import { MouseEventHandler, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -21,6 +20,7 @@ import { QuickSearchData, QuickSearchGroup } from '@/components/quick-search';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { AccessRequest, Doc, Role } from '@/docs/doc-management/';
|
||||
import { useAuth } from '@/features/auth';
|
||||
import { useToast } from '@/hooks';
|
||||
import { useResponsiveStore } from '@/stores';
|
||||
|
||||
import {
|
||||
@@ -52,7 +52,7 @@ type Props = {
|
||||
const DocShareAccessRequestItem = ({ doc, accessRequest }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { isSmallMobile } = useResponsiveStore();
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
const { mutate: acceptDocAccessRequests } = useAcceptDocAccessRequest();
|
||||
const [role, setRole] = useState(accessRequest.role);
|
||||
@@ -209,7 +209,7 @@ export const ButtonAccessRequest = ({
|
||||
page: 1,
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const { mutate: createRequest } = useCreateDocAccessRequest({
|
||||
onSuccess: () => {
|
||||
toast(t('Access request sent successfully.'), VariantType.SUCCESS, {
|
||||
|
||||
+3
-6
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
Button,
|
||||
VariantType,
|
||||
useToastProvider,
|
||||
} from '@gouvfr-lasuite/ui-components';
|
||||
import { Button, VariantType } from '@gouvfr-lasuite/ui-components';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -11,6 +7,7 @@ import { Box, Card } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { Doc, Role } from '@/docs/doc-management';
|
||||
import { User } from '@/features/auth';
|
||||
import { useToast } from '@/hooks';
|
||||
import { useResponsiveStore } from '@/stores';
|
||||
|
||||
import { useCreateDocAccess, useCreateDocInvitation } from '../api';
|
||||
@@ -38,7 +35,7 @@ export const DocShareAddMemberList = ({
|
||||
afterInvite,
|
||||
}: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const { isSmallMobile } = useResponsiveStore();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
|
||||
+3
-2
@@ -1,4 +1,4 @@
|
||||
import { VariantType, useToastProvider } from '@gouvfr-lasuite/ui-components';
|
||||
import { VariantType } from '@gouvfr-lasuite/ui-components';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { css } from 'styled-components';
|
||||
@@ -15,6 +15,7 @@ import { QuickSearchData, QuickSearchGroup } from '@/components/quick-search';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { Doc, Role } from '@/docs/doc-management';
|
||||
import { User } from '@/features/auth';
|
||||
import { useToast } from '@/hooks';
|
||||
|
||||
import { useDocInvitationsInfinite, useUpdateDocInvitation } from '../api';
|
||||
import { Invitation } from '../types';
|
||||
@@ -42,7 +43,7 @@ export const DocShareInvitationItem = ({
|
||||
is_first_connection: false,
|
||||
};
|
||||
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const canUpdate = doc.abilities.accesses_manage;
|
||||
|
||||
const { mutate: updateDocInvitation } = useUpdateDocInvitation({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { VariantType, useToastProvider } from '@gouvfr-lasuite/ui-components';
|
||||
import { VariantType } from '@gouvfr-lasuite/ui-components';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -7,6 +7,7 @@ import { QuickSearchData } from '@/components/quick-search';
|
||||
import { QuickSearchGroup } from '@/components/quick-search/QuickSearchGroup';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { Access, Doc, Role } from '@/docs/doc-management/';
|
||||
import { useToast } from '@/hooks';
|
||||
|
||||
import { useDocAccesses, useUpdateDocAccess } from '../api';
|
||||
import { useWhoAmI } from '../hooks/';
|
||||
@@ -26,7 +27,7 @@ export const DocShareMemberItem = ({
|
||||
}: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { isLastOwner } = useWhoAmI(access);
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
|
||||
const message = isLastOwner
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { VariantType, useToastProvider } from '@gouvfr-lasuite/ui-components';
|
||||
import { VariantType } from '@gouvfr-lasuite/ui-components';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { css } from 'styled-components';
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
getDocLinkRole,
|
||||
useDocUtils,
|
||||
} from '@/docs/doc-management';
|
||||
import { useToast } from '@/hooks';
|
||||
import { useResponsiveStore } from '@/stores';
|
||||
|
||||
import { useUpdateDocLink } from '../api/useUpdateDocLink';
|
||||
@@ -42,7 +43,7 @@ export const DocVisibility = ({ doc }: DocVisibilityProps) => {
|
||||
const { isDesynchronized } = useDocUtils(doc);
|
||||
const { linkModeTranslations, linkReachChoices, linkReachTranslations } =
|
||||
useTranslatedShareSettings();
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
|
||||
const description =
|
||||
docLinkRole === LinkRole.READER
|
||||
|
||||
+2
-2
@@ -3,7 +3,6 @@ import {
|
||||
Modal,
|
||||
ModalSize,
|
||||
VariantType,
|
||||
useToastProvider,
|
||||
} from '@gouvfr-lasuite/ui-components';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { createGlobalStyle } from 'styled-components';
|
||||
@@ -12,6 +11,7 @@ import { Box, Text } from '@/components';
|
||||
import { useThreadStore } from '@/docs/doc-comments/stores/useThreadStore';
|
||||
import { Doc, base64ToYDoc, useProviderStore } from '@/docs/doc-management/';
|
||||
import { useDocContentUpdate } from '@/docs/doc-management/api/useDocContentUpdate';
|
||||
import { useToast } from '@/hooks';
|
||||
|
||||
import { useDocVersion } from '../api';
|
||||
import { KEY_LIST_DOC_VERSIONS } from '../api/useDocVersions';
|
||||
@@ -42,7 +42,7 @@ export const ModalConfirmationVersion = ({
|
||||
versionId,
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const { provider } = useProviderStore();
|
||||
const { threadStore } = useThreadStore();
|
||||
const { mutate: updateDocContent } = useDocContentUpdate({
|
||||
|
||||
+2
-2
@@ -2,7 +2,6 @@ import {
|
||||
ButtonProps,
|
||||
DropdownMenuItem,
|
||||
VariantType,
|
||||
useToastProvider,
|
||||
} from '@gouvfr-lasuite/ui-components';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -14,6 +13,7 @@ import {
|
||||
useRestoreDoc,
|
||||
} from '@/docs/doc-management';
|
||||
import { DocToolBox } from '@/docs/doc-management/components/DocToolBox';
|
||||
import { useToast } from '@/hooks';
|
||||
import MoreIcon from '@/icons/more_horiz.svg';
|
||||
|
||||
import { KEY_LIST_DOC_TRASHBIN } from '../api';
|
||||
@@ -51,7 +51,7 @@ export const DocsGridTrashbinActions = ({
|
||||
doc,
|
||||
}: DocsGridTrashbinActionsProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const { mutate: restoreDoc } = useRestoreDoc({
|
||||
listInvalidQueries: [
|
||||
KEY_LIST_DOC,
|
||||
|
||||
@@ -2,3 +2,4 @@ export * from './useClipboard';
|
||||
export * from './useCmdK';
|
||||
export * from './useDate';
|
||||
export * from './useKeyboardAction';
|
||||
export * from './useToast';
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { VariantType, useToastProvider } from '@gouvfr-lasuite/ui-components';
|
||||
import { VariantType } from '@gouvfr-lasuite/ui-components';
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useToast } from './useToast';
|
||||
|
||||
export const useClipboard = () => {
|
||||
const { toast } = useToastProvider();
|
||||
const { toast } = useToast();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return useCallback(
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import {
|
||||
ToastProviderContext,
|
||||
useToastProvider,
|
||||
} from '@gouvfr-lasuite/ui-components';
|
||||
import { useCallback, useRef } from 'react';
|
||||
|
||||
/**
|
||||
* The provider's `toast` function is recreated every time any toast is shown
|
||||
* anywhere in the app, which breaks memoization for anything that lists it as
|
||||
* a dependency - it once caused the BlockNote editor to fully remount (and
|
||||
* reset scroll) whenever an unrelated toast fired. Use this instead of
|
||||
* `useToastProvider` directly to get a `toast` with a stable identity.
|
||||
*
|
||||
* @TODO Modify the ui-components library to provide a stable toast function directly.
|
||||
*/
|
||||
export const useToast = (): ToastProviderContext => {
|
||||
const { toast } = useToastProvider();
|
||||
const toastRef = useRef(toast);
|
||||
toastRef.current = toast;
|
||||
|
||||
const stableToast = useCallback<ToastProviderContext['toast']>(
|
||||
(...args) => toastRef.current(...args),
|
||||
[],
|
||||
);
|
||||
|
||||
return { toast: stableToast };
|
||||
};
|
||||
Reference in New Issue
Block a user