diff --git a/src/components/Accessibility/NotificationAnnouncer.tsx b/src/components/Accessibility/NotificationAnnouncer.tsx index 7d91d1c52..6f543da2b 100644 --- a/src/components/Accessibility/NotificationAnnouncer.tsx +++ b/src/components/Accessibility/NotificationAnnouncer.tsx @@ -60,8 +60,7 @@ const defaultNotificationFilter: NotificationAnnouncementFilter = () => true; * satisfies this and no extra setup is needed. * * Rendered **without** a provider ancestor it mounts successfully but **announces nothing** — - * `useAriaLiveAnnouncer()` returns a no-op and logs a `console.warn` ("… called outside of an - * AriaLiveAnnouncerProvider"). This is intentional post-F4: the component no longer carries a + * `useAriaLiveAnnouncer()` returns a no-op. This is intentional post-F4: the component no longer carries a * fallback live region, so a single announcer owns all output and there are no duplicate/competing * regions. If you render it outside `Chat`, wrap it in `AriaLiveAnnouncerProvider` + `AriaLiveOutlet` * yourself. diff --git a/src/components/Accessibility/hooks/useIncomingMessageAnnouncements.ts b/src/components/Accessibility/hooks/useIncomingMessageAnnouncements.ts index 0f2d3375b..ca4fe5e86 100644 --- a/src/components/Accessibility/hooks/useIncomingMessageAnnouncements.ts +++ b/src/components/Accessibility/hooks/useIncomingMessageAnnouncements.ts @@ -51,7 +51,7 @@ export const useIncomingMessageAnnouncements = ({ threadList = false, }: UseIncomingMessageAnnouncementsParams) => { const announce = useAriaLiveAnnouncer(); - const { t } = useTranslationContext('useIncomingMessageAnnouncements'); + const { t } = useTranslationContext(); const lastAnnouncementTimestampRef = useRef(0); const flushTimeoutRef = useRef | undefined>(undefined); const announcedMessageIdsRef = useRef(new Set()); diff --git a/src/components/Accessibility/useAriaLiveAnnouncer.ts b/src/components/Accessibility/useAriaLiveAnnouncer.ts index db4448486..c452decde 100644 --- a/src/components/Accessibility/useAriaLiveAnnouncer.ts +++ b/src/components/Accessibility/useAriaLiveAnnouncer.ts @@ -41,16 +41,9 @@ export const AriaLiveAnnouncerContext = createContext< AriaLiveAnnouncerContextValue | undefined >(undefined); -export const useAriaLiveAnnouncer = () => { - const contextValue = useContext(AriaLiveAnnouncerContext); - - if (!contextValue) { - console.warn( - 'The useAriaLiveAnnouncer hook was called outside of an AriaLiveAnnouncerProvider.', - ); - - return noopAnnounce; - } - - return contextValue.announce; -}; +/** + * Announcements are a progressive enhancement: outside an `AriaLiveAnnouncerProvider` this is a + * no-op rather than an error. + */ +export const useAriaLiveAnnouncer = () => + useContext(AriaLiveAnnouncerContext)?.announce ?? noopAnnounce; diff --git a/src/components/Attachment/AttachmentActions.tsx b/src/components/Attachment/AttachmentActions.tsx index 87e4324eb..ef5274ab6 100644 --- a/src/components/Attachment/AttachmentActions.tsx +++ b/src/components/Attachment/AttachmentActions.tsx @@ -46,7 +46,7 @@ const UnMemoizedAttachmentActions = (props: AttachmentActionsProps) => { title, type, } = props; - const { t } = useTranslationContext('UnMemoizedAttachmentActions'); + const { t } = useTranslationContext(); const { announceInteraction } = useInteractionAnnouncements(); const { reserve: reserveFocusReturn, restore: restoreFocusReturn } = useFocusReturn(); const buttonRefs = useRef>([]); diff --git a/src/components/Attachment/Audio.tsx b/src/components/Attachment/Audio.tsx index 8a8e3cb84..edc08cb6a 100644 --- a/src/components/Attachment/Audio.tsx +++ b/src/components/Attachment/Audio.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useContext } from 'react'; import type { Attachment, VoiceRecordingAttachment } from 'stream-chat'; import { @@ -8,7 +8,7 @@ import { import type { AudioPlayerState } from '../AudioPlayback/AudioPlayer'; import { useAudioPlayer } from '../AudioPlayback/WithAudioPlayback'; import { useStateStore } from '../../store'; -import { useComponentContext, useMessageContext } from '../../context'; +import { MessageContext, useComponentContext } from '../../context'; import type { AudioPlayer } from '../AudioPlayback/AudioPlayer'; import { PlayButton } from '../Button/PlayButton'; import { FileIcon } from '../FileIcon'; @@ -102,7 +102,8 @@ export const Audio = (props: AudioProps) => { * with the default SDK components, but can be done with custom API calls.In this case all the Audio * widgets will share the state. */ - const { message } = useMessageContext() ?? {}; + // also rendered from composer previews, where there is no message + const { message } = useContext(MessageContext) ?? {}; const threadInstance = useThreadContext(); const audioPlayer = useAudioPlayer({ diff --git a/src/components/Attachment/LinkPreview/CardAudio.tsx b/src/components/Attachment/LinkPreview/CardAudio.tsx index 1657704d9..28c163b99 100644 --- a/src/components/Attachment/LinkPreview/CardAudio.tsx +++ b/src/components/Attachment/LinkPreview/CardAudio.tsx @@ -1,9 +1,9 @@ import { type AudioPlayerState, ProgressBar, useAudioPlayer } from '../../AudioPlayback'; -import { useMessageContext } from '../../../context'; +import { MessageContext } from '../../../context'; import { useStateStore } from '../../../store'; import { PlayButton } from '../../Button'; import type { AudioProps } from '../Audio'; -import React from 'react'; +import React, { useContext } from 'react'; import { IconLink } from '../../Icons'; import { SafeAnchor } from '../../SafeAnchor'; import type { CardProps } from './Card'; @@ -56,7 +56,8 @@ const AudioWidget = ({ mimeType, src }: { src: string; mimeType?: string }) => { * with the default SDK components, but can be done with custom API calls.In this case all the Audio * widgets will share the state. */ - const { message } = useMessageContext() ?? {}; + // also rendered from link previews, where there is no message + const { message } = useContext(MessageContext) ?? {}; const threadInstance = useThreadContext(); const audioPlayer = useAudioPlayer({ diff --git a/src/components/Attachment/LinkPreview/UnableToRenderCard.tsx b/src/components/Attachment/LinkPreview/UnableToRenderCard.tsx index 7c559c838..d1a429aa4 100644 --- a/src/components/Attachment/LinkPreview/UnableToRenderCard.tsx +++ b/src/components/Attachment/LinkPreview/UnableToRenderCard.tsx @@ -4,7 +4,7 @@ import clsx from 'clsx'; import React from 'react'; export const UnableToRenderCard = ({ type }: { type?: Attachment['type'] }) => { - const { t } = useTranslationContext('Card'); + const { t } = useTranslationContext(); return (
+ items.map((item) => ({ + ...item, + createdAt: item.createdAt ?? message?.created_at, + user: item.user ?? message?.user ?? undefined, + })), + [items, message?.created_at, message?.user], + ); const usesDefaultBaseImage = BaseImage === DefaultBaseImage; const closeModal = useCallback(() => { @@ -114,7 +130,7 @@ export const ModalGallery = ({ closeOnBackgroundClick={closeOnBackgroundClick} GalleryUI={GalleryUI} initialIndex={selectedIndex} - items={items} + items={itemsWithSender} onRequestClose={closeModal} /> diff --git a/src/components/Attachment/UnsupportedAttachment.tsx b/src/components/Attachment/UnsupportedAttachment.tsx index fd2c4dd71..66adeb5b9 100644 --- a/src/components/Attachment/UnsupportedAttachment.tsx +++ b/src/components/Attachment/UnsupportedAttachment.tsx @@ -8,7 +8,7 @@ export type UnsupportedAttachmentProps = { }; export const UnsupportedAttachment = () => { - const { t } = useTranslationContext('UnsupportedAttachment'); + const { t } = useTranslationContext(); return (
{ - const { t } = useTranslationContext('ProgressBar'); + const { t } = useTranslationContext(); const { handleDrag, handleDragStart, diff --git a/src/components/AudioPlayback/components/WaveProgressBar.tsx b/src/components/AudioPlayback/components/WaveProgressBar.tsx index ce11b8cd6..4fee30ae6 100644 --- a/src/components/AudioPlayback/components/WaveProgressBar.tsx +++ b/src/components/AudioPlayback/components/WaveProgressBar.tsx @@ -37,7 +37,7 @@ export const WaveProgressBar = ({ seek, waveformData, }: WaveProgressBarProps) => { - const { t } = useTranslationContext('WaveProgressBar'); + const { t } = useTranslationContext(); const [trackAxisX, setTrackAxisX] = useState<{ barCount: number; barWidth: number; diff --git a/src/components/Avatar/AvatarStack.tsx b/src/components/Avatar/AvatarStack.tsx index b04d2ebf2..0165325b7 100644 --- a/src/components/Avatar/AvatarStack.tsx +++ b/src/components/Avatar/AvatarStack.tsx @@ -17,7 +17,7 @@ export function AvatarStack({ badgeSize?: BadgeSize; capLimit?: number; }) { - const { Avatar = DefaultAvatar } = useComponentContext(AvatarStack.name); + const { Avatar = DefaultAvatar } = useComponentContext(); const displayInfoToRender = useMemo( () => (displayInfo.length > capLimit ? displayInfo.slice(0, capLimit) : displayInfo), diff --git a/src/components/Channel/Channel.tsx b/src/components/Channel/Channel.tsx index 5547bfba4..a3e09a5fc 100644 --- a/src/components/Channel/Channel.tsx +++ b/src/components/Channel/Channel.tsx @@ -154,9 +154,8 @@ const ChannelInner = ( const { LoadingErrorIndicator, LoadingIndicator = DefaultLoadingIndicator } = useComponentContext(); - const { client, latestMessageDatesByChannels, searchController } = - useChatContext('Channel'); - const { t } = useTranslationContext('Channel'); + const { client, latestMessageDatesByChannels, searchController } = useChatContext(); + const { t } = useTranslationContext(); const windowsEmojiClass = useImageFlagEmojisOnWindowsClass(); const channelConfig = useChannelConfig({ cid: channel.cid }); diff --git a/src/components/Channel/hooks/useChannelConfig.ts b/src/components/Channel/hooks/useChannelConfig.ts index e430dd904..c25286ca7 100644 --- a/src/components/Channel/hooks/useChannelConfig.ts +++ b/src/components/Channel/hooks/useChannelConfig.ts @@ -8,7 +8,7 @@ const channelConfigsSelector = (value: ChannelConfigsState) => ({ // todo: why is channel config stored on client? export const useChannelConfig = ({ cid }: { cid: string | undefined }) => { - const { client } = useChatContext('useChannelConfig'); + const { client } = useChatContext(); const channelConfigsState = useStateStore(client.configsStore, channelConfigsSelector); if (!cid) return undefined; diff --git a/src/components/Channel/hooks/useChannelContainerClasses.ts b/src/components/Channel/hooks/useChannelContainerClasses.ts index a71707845..14fceaa45 100644 --- a/src/components/Channel/hooks/useChannelContainerClasses.ts +++ b/src/components/Channel/hooks/useChannelContainerClasses.ts @@ -2,7 +2,7 @@ import { useChatContext } from '../../../context/ChatContext'; import type { ChatContextValue } from '../../../context/ChatContext'; export const useImageFlagEmojisOnWindowsClass = () => { - const { useImageFlagEmojisOnWindows } = useChatContext('Channel'); + const { useImageFlagEmojisOnWindows } = useChatContext(); return useImageFlagEmojisOnWindows && navigator.userAgent.match(/Win/) ? 'str-chat--windows-flags' : ''; diff --git a/src/components/ChannelHeader/ChannelHeader.tsx b/src/components/ChannelHeader/ChannelHeader.tsx index 6eb42ce0a..14d03c9a6 100644 --- a/src/components/ChannelHeader/ChannelHeader.tsx +++ b/src/components/ChannelHeader/ChannelHeader.tsx @@ -16,7 +16,7 @@ const textComposerTypingSelector = ({ typing }: TextComposerState) => ({ typing const ChannelHeaderSubtitle = () => { const channel = useChannel(); const channelConfig = useChannelConfig({ cid: channel.cid }); - const { client } = useChatContext('ChannelHeaderSubtitle'); + const { client } = useChatContext(); const messageComposer = useMessageComposerController(); const { typing = {} } = useStateStore(messageComposer.textComposer?.state, textComposerTypingSelector) ?? {}; diff --git a/src/components/ChannelListItem/ChannelListItem.tsx b/src/components/ChannelListItem/ChannelListItem.tsx index 75e5d3a1f..a04830282 100644 --- a/src/components/ChannelListItem/ChannelListItem.tsx +++ b/src/components/ChannelListItem/ChannelListItem.tsx @@ -22,6 +22,7 @@ import { useWorkspaceNavigation, } from '../../context'; import { useChannelMembershipState } from '../ChannelList'; +import { requireContext } from '../../context/requireContext'; export type ChannelListItemUIProps = ChannelListItemProps & { /** @@ -73,11 +74,16 @@ export type ChannelListItemProps = { watchers?: { limit?: number; offset?: number }; }; -const ChannelListItemContext = React.createContext<{ channel: Channel }>({ - channel: null as unknown as Channel, -}); +const ChannelListItemContext = React.createContext<{ channel: Channel } | undefined>( + undefined, +); -export const useChannelListItemContext = () => useContext(ChannelListItemContext); +export const useChannelListItemContext = () => + requireContext( + useContext(ChannelListItemContext), + 'useChannelListItemContext', + 'ChannelListItemUI', + ); const lastMessageSelector = ({ lastMessage }: MessagePaginatorAggregateState) => ({ lastMessage: lastMessage ?? undefined, @@ -86,7 +92,7 @@ const lastMessageSelector = ({ lastMessage }: MessagePaginatorAggregateState) => export const ChannelListItem = (props: ChannelListItemProps) => { const { active, channel, channelUpdateCount } = props; const { ChannelListItemUI = DefaultChannelListItemUI } = useComponentContext(); - const { client } = useChatContext('ChannelPreview'); + const { client } = useChatContext(); // Active = THIS channel is currently open in the workspace. Keyed on the channel's own // cid (never "the first channel slot"), so multiple open channels each highlight independently. const channelOpenInSlot = useWorkspaceNavigation().isChannelActive( diff --git a/src/components/ChannelListItem/ChannelListItemTimestamp.tsx b/src/components/ChannelListItem/ChannelListItemTimestamp.tsx index 4ed9161f4..9518c94f5 100644 --- a/src/components/ChannelListItem/ChannelListItemTimestamp.tsx +++ b/src/components/ChannelListItem/ChannelListItemTimestamp.tsx @@ -12,7 +12,7 @@ export type ChannelListItemTimestampProps = { export function ChannelListItemTimestamp({ previewedMessage, }: ChannelListItemTimestampProps) { - const { t, tDateTimeParser } = useTranslationContext('ChannelListItemTimestamp'); + const { t, tDateTimeParser } = useTranslationContext(); const timestamp = previewedMessage?.created_at; const normalizedTimestamp = diff --git a/src/components/ChannelListItem/ChannelListItemUI.tsx b/src/components/ChannelListItem/ChannelListItemUI.tsx index 977e97f7c..414bb657a 100644 --- a/src/components/ChannelListItem/ChannelListItemUI.tsx +++ b/src/components/ChannelListItem/ChannelListItemUI.tsx @@ -40,8 +40,8 @@ const UnMemoizedChannelListItemUI = (props: ChannelListItemUIProps) => { ChannelListItemActionButtons = DefaultChannelListItemActionButtons, SummarizedMessagePreview = DefaultSummarizedMessagePreview, } = useComponentContext(); - const { client, isMessageAIGenerated } = useChatContext('ChannelListItemUI'); - const { t, tDateTimeParser, userLanguage } = useTranslationContext('ChannelListItemUI'); + const { client, isMessageAIGenerated } = useChatContext(); + const { t, tDateTimeParser, userLanguage } = useTranslationContext(); const { openChannel } = useWorkspaceNavigation(); const { announceInteraction } = useInteractionAnnouncements(); diff --git a/src/components/ChannelListItem/hooks/useChannelDisplayName.ts b/src/components/ChannelListItem/hooks/useChannelDisplayName.ts index 20139c251..c08470a59 100644 --- a/src/components/ChannelListItem/hooks/useChannelDisplayName.ts +++ b/src/components/ChannelListItem/hooks/useChannelDisplayName.ts @@ -45,8 +45,8 @@ function computeChannelDisplayName( export const useChannelDisplayName = ( channel: Channel | undefined, ): string | undefined => { - const { client } = useChatContext('useChannelDisplayName'); - const { t } = useTranslationContext('useChannelDisplayName'); + const { client } = useChatContext(); + const { t } = useTranslationContext(); const directMessageLabel = t( 'channelListItem.channelDisplayName.directMessage.label', 'Direct message', diff --git a/src/components/ChannelListItem/hooks/useIsChannelMuted.ts b/src/components/ChannelListItem/hooks/useIsChannelMuted.ts index 88d2c15ee..925f38ce9 100644 --- a/src/components/ChannelListItem/hooks/useIsChannelMuted.ts +++ b/src/components/ChannelListItem/hooks/useIsChannelMuted.ts @@ -20,7 +20,7 @@ const getMuteStatus = (channel: Channel) => : { createdAt: null, expiresAt: null, muted: false }; export const useIsChannelMuted = (channel: Channel) => { - const { client } = useChatContext('useIsChannelMuted'); + const { client } = useChatContext(); const [muted, setMuted] = useState(() => getMuteStatus(channel)); diff --git a/src/components/DateSeparator/DateSeparator.tsx b/src/components/DateSeparator/DateSeparator.tsx index d130406cf..95a913b78 100644 --- a/src/components/DateSeparator/DateSeparator.tsx +++ b/src/components/DateSeparator/DateSeparator.tsx @@ -32,7 +32,7 @@ const UnMemoizedDateSeparator = (props: DateSeparatorProps) => { ...restTimestampFormatterOptions } = props; - const { t, tDateTimeParser } = useTranslationContext('DateSeparator'); + const { t, tDateTimeParser } = useTranslationContext(); const formattedDate = getDateString({ calendar, diff --git a/src/components/Dialog/components/ContextMenu.tsx b/src/components/Dialog/components/ContextMenu.tsx index 5f35cb33b..012f07a79 100644 --- a/src/components/Dialog/components/ContextMenu.tsx +++ b/src/components/Dialog/components/ContextMenu.tsx @@ -22,6 +22,7 @@ import { useComponentContext, useTranslationContext } from '../../../context'; import { createRovingFocusKeyDownHandler } from '../../../a11y/a11yUtils'; import { VisuallyHidden } from '../../VisuallyHidden'; import { useStableId } from '../../UtilityComponents/useStableId'; +import { requireContext } from '../../../context/requireContext'; /** * ContextMenu module @@ -589,7 +590,7 @@ const ContextMenuContext = React.createContext - useContext(ContextMenuContext) as ContextMenuContextValue; + requireContext(useContext(ContextMenuContext), 'useContextMenuContext', 'ContextMenu'); type ContextMenuLevel = { focusRestoreRequest?: ContextMenuFocusRestoreRequest; diff --git a/src/components/EmptyStateIndicator/EmptyStateIndicator.tsx b/src/components/EmptyStateIndicator/EmptyStateIndicator.tsx index 79d7bb63e..b4fe2ff01 100644 --- a/src/components/EmptyStateIndicator/EmptyStateIndicator.tsx +++ b/src/components/EmptyStateIndicator/EmptyStateIndicator.tsx @@ -13,7 +13,7 @@ export type EmptyStateIndicatorProps = { const UnMemoizedEmptyStateIndicator = (props: EmptyStateIndicatorProps) => { const { listType, messageText } = props; - const { t } = useTranslationContext('EmptyStateIndicator'); + const { t } = useTranslationContext(); if (listType === 'thread') return null; diff --git a/src/components/Form/SwitchField.tsx b/src/components/Form/SwitchField.tsx index ff879c8e0..942a150db 100644 --- a/src/components/Form/SwitchField.tsx +++ b/src/components/Form/SwitchField.tsx @@ -51,7 +51,7 @@ export const SwitchField = ({ // Read the announcer optionally: a SwitchField may render outside an announcer provider (e.g. in // isolation), where it simply stays silent rather than warning. const announce = useContext(AriaLiveAnnouncerContext)?.announce; - const { t } = useTranslationContext('SwitchField'); + const { t } = useTranslationContext(); const [uncontrolledChecked, setUncontrolledChecked] = useState(Boolean(defaultChecked)); const isControlled = checked !== undefined; diff --git a/src/components/Gallery/GalleryContext.tsx b/src/components/Gallery/GalleryContext.tsx index c7d1c081c..a03adb1ba 100644 --- a/src/components/Gallery/GalleryContext.tsx +++ b/src/components/Gallery/GalleryContext.tsx @@ -1,12 +1,18 @@ import { createContext, useContext } from 'react'; +import type { UserResponse } from 'stream-chat'; +import { requireContext } from '../../context/requireContext'; import { toBaseImageDescriptors } from '../BaseImage'; import type { BaseImageProps } from '../BaseImage'; import type { Dimensions } from '../../types/types'; export type GalleryItem = Omit & { + /** When the media was shared; drives the gallery header timestamp. */ + createdAt?: string | Date; dimensions?: Dimensions; imageUrl?: string; + /** User who shared the media; drives the gallery header title. */ + user?: UserResponse; videoThumbnailUrl?: string; videoUrl?: string; }; @@ -51,16 +57,5 @@ export type GalleryContextValue = { export const GalleryContext = createContext(undefined); -export const useGalleryContext = () => { - const contextValue = useContext(GalleryContext); - - if (!contextValue) { - console.warn( - `The useGalleryContext hook was called outside of the GalleryContext provider. Make sure this hook is called within a child of the Gallery component.`, - ); - - return {} as GalleryContextValue; - } - - return contextValue; -}; +export const useGalleryContext = () => + requireContext(useContext(GalleryContext), 'useGalleryContext', 'Gallery'); diff --git a/src/components/Gallery/GalleryHeader.tsx b/src/components/Gallery/GalleryHeader.tsx index 0c029b777..6e576edc3 100644 --- a/src/components/Gallery/GalleryHeader.tsx +++ b/src/components/Gallery/GalleryHeader.tsx @@ -4,28 +4,56 @@ import { sanitizeUrl } from '@braintree/sanitize-url'; import { type GalleryItem } from './GalleryContext'; import { Button } from '../Button'; import { IconArrowDownCircle, IconXmark } from '../Icons'; -import { MessageTimestamp as DefaultMessageTimestamp } from '../Message/MessageTimestamp'; -import { - ModalContext, - useComponentContext, - useMessageContext, - useTranslationContext, -} from '../../context'; +import { ModalContext, useChatContext, useTranslationContext } from '../../context'; +import { getDateString, isDate } from '../../i18n/utils'; type GalleryHeaderProps = { currentItem: GalleryItem; }; +const normalizeTimestamp = (timestamp: GalleryItem['createdAt']) => { + if (!timestamp) return undefined; + return isDate(timestamp) ? timestamp.toISOString() : timestamp; +}; + +/** + * Reads the timestamp off the gallery item: the gallery renders outside any `MessageProvider`, and + * channel media mixes items from many messages. + */ +const GalleryTimestamp = ({ createdAt }: Pick) => { + const { t, tDateTimeParser } = useTranslationContext(); + const normalizedTimestamp = normalizeTimestamp(createdAt); + + const when = useMemo( + () => + getDateString({ + messageCreatedAt: normalizedTimestamp, + t, + tDateTimeParser, + timestampTranslationKey: 'timestamp.GalleryTimestamp', + }), + [normalizedTimestamp, t, tDateTimeParser], + ); + + if (!when) return null; + + return ( + + ); +}; + export const GalleryHeader = ({ currentItem }: GalleryHeaderProps) => { const { t } = useTranslationContext(); - const { MessageTimestamp = DefaultMessageTimestamp } = useComponentContext('GalleryUI'); - const { isMyMessage, message } = useMessageContext('GalleryUI'); + const { client } = useChatContext(); const modalContext = useContext(ModalContext); + const { createdAt, user } = currentItem; const headerTitle = - (isMyMessage?.() && t('common.you.label', 'You')) || - message?.user?.name || - message?.user?.id || + (!!user?.id && user.id === client.userID && t('common.you.label', 'You')) || + user?.name || + user?.id || currentItem.title || t('common.userUploadedContent.label', 'User uploaded content'); const downloadUrl = useMemo(() => { @@ -44,9 +72,7 @@ export const GalleryHeader = ({ currentItem }: GalleryHeaderProps) => {