@linktr.ee/messaging-react 2.3.0-rc-1779427772 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{Card-DKp7ijLV.js → Card-4takoN_-.js} +6 -6
- package/dist/{Card-DKp7ijLV.js.map → Card-4takoN_-.js.map} +1 -1
- package/dist/{Card-Djm6JjNo.js → Card-BuROm0u7.js} +19 -19
- package/dist/{Card-Djm6JjNo.js.map → Card-BuROm0u7.js.map} +1 -1
- package/dist/{Card-BlzGsGam.cjs → Card-CexShqpK.cjs} +2 -2
- package/dist/{Card-BlzGsGam.cjs.map → Card-CexShqpK.cjs.map} +1 -1
- package/dist/{Card-BkWwtS0b.cjs → Card-CgpHBx-W.cjs} +2 -2
- package/dist/{Card-BkWwtS0b.cjs.map → Card-CgpHBx-W.cjs.map} +1 -1
- package/dist/{Card-B7yHs01-.js → Card-DdpdnSh_.js} +16 -16
- package/dist/{Card-B7yHs01-.js.map → Card-DdpdnSh_.js.map} +1 -1
- package/dist/{Card-DApWNv5V.cjs → Card-ot16XqS2.cjs} +2 -2
- package/dist/{Card-DApWNv5V.cjs.map → Card-ot16XqS2.cjs.map} +1 -1
- package/dist/{LockedThumbnail-BjF6khtg.cjs → LockedThumbnail-CydtYOSA.cjs} +2 -2
- package/dist/{LockedThumbnail-BjF6khtg.cjs.map → LockedThumbnail-CydtYOSA.cjs.map} +1 -1
- package/dist/{LockedThumbnail-pm6jo2B4.js → LockedThumbnail-Drsh4B5o.js} +8 -8
- package/dist/{LockedThumbnail-pm6jo2B4.js.map → LockedThumbnail-Drsh4B5o.js.map} +1 -1
- package/dist/assets/index.css +1 -1
- package/dist/index-BCbVXFHI.js +4698 -0
- package/dist/index-BCbVXFHI.js.map +1 -0
- package/dist/index-CQ913euH.cjs +2 -0
- package/dist/index-CQ913euH.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +22 -13
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/ChannelView.tsx +2 -8
- package/src/components/CustomMessage/CustomMessage.stories.tsx +0 -140
- package/src/components/CustomMessage/index.tsx +15 -20
- package/src/components/MessageAttachment/Image/ImageAttachment.stories.tsx +8 -5
- package/src/components/MessageAttachment/Image/index.tsx +7 -1
- package/src/components/MessageAttachment/MessageAttachment.test.tsx +200 -19
- package/src/components/MessageAttachment/Pdf/index.tsx +14 -15
- package/src/components/MessageAttachment/Video/VideoAttachment.stories.tsx +2 -2
- package/src/components/MessageAttachment/Video/index.tsx +11 -2
- package/src/components/MessageAttachment/_shared/CarouselNav.tsx +47 -0
- package/src/components/MessageAttachment/_shared/DownloadAction.tsx +27 -27
- package/src/components/MessageAttachment/_shared/ImageViewer.tsx +59 -261
- package/src/components/MessageAttachment/_shared/PdfViewer.tsx +56 -30
- package/src/components/MessageAttachment/_shared/VideoViewer.tsx +53 -109
- package/src/components/MessageAttachment/_shared/ViewerShell.tsx +127 -107
- package/src/components/MessageAttachment/_shared/useCarousel.ts +103 -0
- package/src/components/MessageAttachment/index.tsx +18 -9
- package/src/components/MessageAttachment/types.ts +1 -1
- package/src/styles.css +177 -85
- package/dist/index-7sLuX6s4.cjs +0 -18
- package/dist/index-7sLuX6s4.cjs.map +0 -1
- package/dist/index-Co-LV7yc.js +0 -8220
- package/dist/index-Co-LV7yc.js.map +0 -1
- package/src/components/CustomMessage/CustomMessageActions.tsx +0 -35
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-CQ913euH.cjs");exports.ActionButton=e.ActionButton;exports.Avatar=e.Avatar;exports.ChannelEmptyState=e.ChannelEmptyState;exports.ChannelList=e.ChannelList;exports.ChannelView=e.ChannelView;exports.CustomMessageProvider=e.CustomMessageProvider;exports.FaqList=e.FaqList;exports.FaqListItem=e.FaqListItem;exports.LinkAttachment=e.LinkAttachment;exports.LockedAttachment=e.LockedAttachment;exports.MediaMessage=e.MediaMessage;exports.MessageAttachment=e.MessageAttachment;exports.MessageVoteButtons=e.MessageVoteButtons;exports.MessagingProvider=e.MessagingProvider;exports.MessagingShell=e.MessagingShell;exports.buildCompactMetaLabel=e.buildCompactMetaLabel;exports.formatFileSize=e.formatFileSize;exports.formatRelativeTime=e.formatRelativeTime;exports.getFileExtensionLabel=e.getFileExtensionLabel;exports.getMessageDisplayText=e.getMessageDisplayText;exports.isLinkAttachment=e.isLinkAttachment;exports.isUuidLike=e.isUuidLike;exports.messageAttachmentGroupPositionFromStream=e.bubbleGroupPositionFromStream;exports.normalizeLanguageCode=e.normalizeLanguageCode;exports.resolveLinkAttachment=e.resolveLinkAttachment;exports.resolveMediaFromMessage=e.resolveMediaFromMessage;exports.resolveParticipantDisplayName=e.resolveParticipantDisplayName;exports.useCustomMessage=e.useCustomMessage;exports.useMessageVote=e.useMessageVote;exports.useMessaging=e.useMessaging;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.d.ts
CHANGED
|
@@ -428,7 +428,7 @@ declare interface ImageAttachmentSharedProps extends MessageAttachmentBaseProps
|
|
|
428
428
|
/** Single image — convenience for the most common case. */
|
|
429
429
|
src?: string;
|
|
430
430
|
alt?: string;
|
|
431
|
-
/** Filename
|
|
431
|
+
/** Filename used as the viewer dialog's accessible name. */
|
|
432
432
|
filename?: string;
|
|
433
433
|
/**
|
|
434
434
|
* Stacked images. Takes precedence over `src` when set. Renders a
|
|
@@ -703,13 +703,15 @@ declare type MediaPreloadMode = 'none' | 'metadata' | 'auto';
|
|
|
703
703
|
*
|
|
704
704
|
* - Image / Video render a 1 / 2 / 3 / 4-tile grid (5+ collapse
|
|
705
705
|
* into a `+N` overflow tile). Activating any tile opens the
|
|
706
|
-
* built-in `ImageViewer` / `VideoViewer` at that index
|
|
707
|
-
*
|
|
706
|
+
* built-in `ImageViewer` / `VideoViewer` at that index; when
|
|
707
|
+
* `items.length > 1` the lightbox becomes a carousel (prev / next
|
|
708
|
+
* chrome, ArrowLeft / ArrowRight, current / total counter) so the
|
|
709
|
+
* user can browse siblings without closing the modal.
|
|
708
710
|
* - Pdf / Audio / File render their compact rows / players in a
|
|
709
711
|
* vertical stack with an 8px gap between rows. Each row keeps
|
|
710
|
-
* its own activation target — Pdf opens the
|
|
711
|
-
* index, Audio gets its own native player,
|
|
712
|
-
* the asset for that row.
|
|
712
|
+
* its own activation target — Pdf opens the carousel-aware
|
|
713
|
+
* `PdfViewer` at that index, Audio gets its own native player,
|
|
714
|
+
* and File downloads the asset for that row.
|
|
713
715
|
*
|
|
714
716
|
* The Composer surface accepts only a single attachment at a time,
|
|
715
717
|
* so its props omit `items` / `text`.
|
|
@@ -720,10 +722,17 @@ declare type MediaPreloadMode = 'none' | 'metadata' | 'auto';
|
|
|
720
722
|
* message. Sent / Received wrap the media in the shared bubble chrome.
|
|
721
723
|
*
|
|
722
724
|
* Image / Video / Pdf are interactive in every state (Composer, Sent,
|
|
723
|
-
* Received) — clicks open the corresponding native
|
|
724
|
-
*
|
|
725
|
-
*
|
|
726
|
-
*
|
|
725
|
+
* Received) — clicks open the corresponding native lightbox `<dialog>`,
|
|
726
|
+
* which centers the media at reasonable max dimensions (Escape and
|
|
727
|
+
* backdrop click also dismiss). The Image viewer adds an explicit
|
|
728
|
+
* download button to the chrome; the Video viewer relies on the
|
|
729
|
+
* native `<video controls>` download menu, and the Pdf viewer
|
|
730
|
+
* inherits the browser's built-in PDF download. Sibling-row Download
|
|
731
|
+
* buttons on Pdf / File and the native `<audio>` controls expose
|
|
732
|
+
* downloads outside the viewer too. The lightbox chrome is styled
|
|
733
|
+
* with plain CSS (`.mes-media-viewer*`) so the package's shipped
|
|
734
|
+
* stylesheet is enough to render the viewer correctly without a
|
|
735
|
+
* Tailwind dependency in the consumer.
|
|
727
736
|
*
|
|
728
737
|
* # Lazy-loading defaults
|
|
729
738
|
*
|
|
@@ -976,7 +985,7 @@ export declare interface MessageAttachmentPdfComposerProps extends ComposerExtra
|
|
|
976
985
|
/** A single PDF inside a Pdf attachment (single or stacked). */
|
|
977
986
|
export declare interface MessageAttachmentPdfItem {
|
|
978
987
|
src: string;
|
|
979
|
-
/** Filename — drives the title + the meta line + the viewer
|
|
988
|
+
/** Filename — drives the row title + the meta line + the viewer dialog's accessible name. */
|
|
980
989
|
filename?: string;
|
|
981
990
|
/** File size in bytes — formatted into the `EXT · SIZE` meta line. */
|
|
982
991
|
fileSize?: number;
|
|
@@ -1190,7 +1199,7 @@ declare type PaymentStatus = 'pending' | 'paid' | 'failed' | 'refunded';
|
|
|
1190
1199
|
declare interface PdfAttachmentSharedProps extends MessageAttachmentBaseProps {
|
|
1191
1200
|
/** Single PDF — convenience for the most common case. */
|
|
1192
1201
|
src?: string;
|
|
1193
|
-
/** Filename — drives the title + the meta line + the viewer
|
|
1202
|
+
/** Filename — drives the row title + the meta line + the viewer dialog's accessible name. */
|
|
1194
1203
|
filename?: string;
|
|
1195
1204
|
/** File size in bytes — formatted into the `EXT · SIZE` meta line. */
|
|
1196
1205
|
fileSize?: number;
|
|
@@ -1295,7 +1304,7 @@ declare interface VideoAttachmentSharedProps extends MessageAttachmentBaseProps
|
|
|
1295
1304
|
poster?: string;
|
|
1296
1305
|
/** MIME type hint — typed onto the inline `<source>` element. */
|
|
1297
1306
|
mimeType?: string;
|
|
1298
|
-
/** Filename
|
|
1307
|
+
/** Filename used as the viewer dialog's accessible name. */
|
|
1299
1308
|
filename?: string;
|
|
1300
1309
|
/**
|
|
1301
1310
|
* Stacked videos. Takes precedence over `src` when set. Renders a
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as e, b as t, C as i, c as n, d as o, e as m, F as g, f as l, L as r, h as M, M as u, i as L, j as c, k as h, l as d, m as p, n as v, o as A, p as C, q as F, s as k, t as b, u as f, v as x, w as y, x as P, y as S, z as q, B as z, D as B } from "./index-
|
|
1
|
+
import { a as e, b as t, C as i, c as n, d as o, e as m, F as g, f as l, L as r, h as M, M as u, i as L, j as c, k as h, l as d, m as p, n as v, o as A, p as C, q as F, s as k, t as b, u as f, v as x, w as y, x as P, y as S, z as q, B as z, D as B } from "./index-BCbVXFHI.js";
|
|
2
2
|
export {
|
|
3
3
|
e as ActionButton,
|
|
4
4
|
t as Avatar,
|
package/package.json
CHANGED
|
@@ -26,7 +26,6 @@ import { Avatar } from './Avatar'
|
|
|
26
26
|
import { ChannelInfoDialog } from './ChannelInfoDialog'
|
|
27
27
|
import { CustomDateSeparator } from './CustomDateSeparator'
|
|
28
28
|
import { CustomMessage } from './CustomMessage'
|
|
29
|
-
import { CustomMessageActions } from './CustomMessage/CustomMessageActions'
|
|
30
29
|
import { CustomMessageInput } from './CustomMessageInput'
|
|
31
30
|
import { CustomSystemMessage } from './CustomSystemMessage'
|
|
32
31
|
import CustomTypingIndicator from './CustomTypingIndicator'
|
|
@@ -36,7 +35,6 @@ import { LoadingState } from './MessagingShell/LoadingState'
|
|
|
36
35
|
|
|
37
36
|
const ICON_BTN_CLASS =
|
|
38
37
|
'size-10 rounded-full bg-[#F1F0EE] hover:bg-[#E5E4E1] flex items-center justify-center transition-colors duration-150 focus-ring'
|
|
39
|
-
|
|
40
38
|
const DM_AGENT_HEADER_HELPER_TEXT = 'Replies instantly with AI assistant'
|
|
41
39
|
|
|
42
40
|
/**
|
|
@@ -376,12 +374,7 @@ const ChannelViewInner: React.FC<{
|
|
|
376
374
|
|
|
377
375
|
return (
|
|
378
376
|
<>
|
|
379
|
-
<WithComponents
|
|
380
|
-
overrides={{
|
|
381
|
-
Message: MessageOverride,
|
|
382
|
-
MessageActions: CustomMessageActions,
|
|
383
|
-
}}
|
|
384
|
-
>
|
|
377
|
+
<WithComponents overrides={{ Message: MessageOverride }}>
|
|
385
378
|
<Window>
|
|
386
379
|
{/* Custom Channel Header */}
|
|
387
380
|
<div key="lt-channel-header" className="p-4">
|
|
@@ -411,6 +404,7 @@ const ChannelViewInner: React.FC<{
|
|
|
411
404
|
<MessageList
|
|
412
405
|
hideDeletedMessages
|
|
413
406
|
hideNewMessageSeparator={false}
|
|
407
|
+
messageActions={undefined}
|
|
414
408
|
/>
|
|
415
409
|
</div>
|
|
416
410
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import '../../stream-custom-data'
|
|
2
2
|
|
|
3
3
|
import type { Meta, StoryFn } from '@storybook/react'
|
|
4
|
-
import { expect, userEvent, within } from '@storybook/test'
|
|
5
4
|
import React, { useEffect } from 'react'
|
|
6
5
|
import {
|
|
7
6
|
Channel as ChannelType,
|
|
@@ -14,7 +13,6 @@ import {
|
|
|
14
13
|
MessageList,
|
|
15
14
|
MessageUIComponentProps,
|
|
16
15
|
Window,
|
|
17
|
-
WithComponents,
|
|
18
16
|
} from 'stream-chat-react'
|
|
19
17
|
|
|
20
18
|
import {
|
|
@@ -24,8 +22,6 @@ import {
|
|
|
24
22
|
} from '../../stories/decorators/storyUser'
|
|
25
23
|
import CustomTypingIndicator from '../CustomTypingIndicator'
|
|
26
24
|
|
|
27
|
-
import { CustomMessageActions } from './CustomMessageActions'
|
|
28
|
-
|
|
29
25
|
import { CustomMessage } from './index'
|
|
30
26
|
|
|
31
27
|
const meta: Meta = {
|
|
@@ -62,8 +58,6 @@ const createMockChannel = async (
|
|
|
62
58
|
|
|
63
59
|
const channelData = {
|
|
64
60
|
members: [storyUsers.creator.id, storyUsers.visitor.id],
|
|
65
|
-
// Required for useUserRole: canDelete needs delete-own-message, canFlag needs flag-message
|
|
66
|
-
own_capabilities: ['delete-own-message', 'flag-message'],
|
|
67
61
|
}
|
|
68
62
|
|
|
69
63
|
const channel = client.channel(
|
|
@@ -358,8 +352,6 @@ LockedAttachment.args = {
|
|
|
358
352
|
],
|
|
359
353
|
}
|
|
360
354
|
|
|
361
|
-
|
|
362
|
-
|
|
363
355
|
export const ChatbotVariants: StoryFn<TemplateProps> = Template.bind({})
|
|
364
356
|
ChatbotVariants.args = {
|
|
365
357
|
messages: [
|
|
@@ -453,135 +445,3 @@ WithTypingIndicatorComparison.parameters = {
|
|
|
453
445
|
},
|
|
454
446
|
},
|
|
455
447
|
}
|
|
456
|
-
|
|
457
|
-
// ─── Message Actions ──────────────────────────────────────────────────────────
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
* Same as TemplateInner but wraps with WithComponents so CustomMessageActions
|
|
461
|
-
* is wired in — matching what ChannelView does in production.
|
|
462
|
-
*/
|
|
463
|
-
const WithActionsTemplateInner: React.FC<{
|
|
464
|
-
currentUser: StoryUser
|
|
465
|
-
messages: TemplateProps['messages']
|
|
466
|
-
}> = ({ currentUser, messages }) => {
|
|
467
|
-
const [client] = React.useState(() => {
|
|
468
|
-
const c = new StreamChat('mock-api-key', { allowServerSideConnect: true })
|
|
469
|
-
c.userID = currentUser.id
|
|
470
|
-
c.user = currentUser
|
|
471
|
-
return c
|
|
472
|
-
})
|
|
473
|
-
|
|
474
|
-
const [channel, setChannel] = React.useState<ChannelType | null>(null)
|
|
475
|
-
|
|
476
|
-
useEffect(() => {
|
|
477
|
-
createMockChannel(client, messages).then(setChannel)
|
|
478
|
-
}, [client, messages])
|
|
479
|
-
|
|
480
|
-
const MessageComponent = React.useMemo(() => {
|
|
481
|
-
return function CustomMessageComponent(props: MessageUIComponentProps) {
|
|
482
|
-
return <CustomMessage {...props} />
|
|
483
|
-
}
|
|
484
|
-
}, [])
|
|
485
|
-
|
|
486
|
-
if (!channel) {
|
|
487
|
-
return <div className="p-4">Loading...</div>
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
return (
|
|
491
|
-
<Chat client={client}>
|
|
492
|
-
<div className="h-screen w-full bg-white">
|
|
493
|
-
<Channel channel={channel} TypingIndicator={CustomTypingIndicator}>
|
|
494
|
-
<WithComponents
|
|
495
|
-
overrides={{
|
|
496
|
-
Message: MessageComponent,
|
|
497
|
-
MessageActions: CustomMessageActions,
|
|
498
|
-
}}
|
|
499
|
-
>
|
|
500
|
-
<Window>
|
|
501
|
-
<MessageList />
|
|
502
|
-
</Window>
|
|
503
|
-
</WithComponents>
|
|
504
|
-
</Channel>
|
|
505
|
-
</div>
|
|
506
|
-
</Chat>
|
|
507
|
-
)
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
const WithActionsTemplate: StoryFn<TemplateProps> = ({
|
|
511
|
-
currentUser = storyUsers.creator,
|
|
512
|
-
messages,
|
|
513
|
-
}) => (
|
|
514
|
-
<WithActionsTemplateInner
|
|
515
|
-
key={currentUser.id}
|
|
516
|
-
currentUser={currentUser}
|
|
517
|
-
messages={messages}
|
|
518
|
-
/>
|
|
519
|
-
)
|
|
520
|
-
|
|
521
|
-
export const DeleteOwnMessage: StoryFn<TemplateProps> =
|
|
522
|
-
WithActionsTemplate.bind({})
|
|
523
|
-
DeleteOwnMessage.args = {
|
|
524
|
-
currentUser: storyUsers.creator,
|
|
525
|
-
messages: [
|
|
526
|
-
{
|
|
527
|
-
id: 'msg-1',
|
|
528
|
-
text: 'Hey, how are you?',
|
|
529
|
-
user: storyUsers.visitor,
|
|
530
|
-
},
|
|
531
|
-
{
|
|
532
|
-
id: 'msg-2',
|
|
533
|
-
text: 'Doing great — hover me to delete!',
|
|
534
|
-
user: storyUsers.creator,
|
|
535
|
-
},
|
|
536
|
-
],
|
|
537
|
-
}
|
|
538
|
-
DeleteOwnMessage.play = async ({ canvasElement }) => {
|
|
539
|
-
const canvas = within(canvasElement)
|
|
540
|
-
const ownBubble = await canvas.findByText('Doing great — hover me to delete!')
|
|
541
|
-
await userEvent.hover(ownBubble)
|
|
542
|
-
const toggle = await canvas.findByTestId('message-actions-toggle-button')
|
|
543
|
-
await userEvent.click(toggle)
|
|
544
|
-
await expect(canvas.getByText('Delete')).toBeInTheDocument()
|
|
545
|
-
}
|
|
546
|
-
DeleteOwnMessage.parameters = {
|
|
547
|
-
docs: {
|
|
548
|
-
description: {
|
|
549
|
-
story:
|
|
550
|
-
'Current user hovers their own message. Only "Delete" is shown — "Report" is hidden.',
|
|
551
|
-
},
|
|
552
|
-
},
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
export const ReportOthersMessage: StoryFn<TemplateProps> =
|
|
556
|
-
WithActionsTemplate.bind({})
|
|
557
|
-
ReportOthersMessage.args = {
|
|
558
|
-
currentUser: storyUsers.creator,
|
|
559
|
-
messages: [
|
|
560
|
-
{
|
|
561
|
-
id: 'msg-1',
|
|
562
|
-
text: 'Hover me to report!',
|
|
563
|
-
user: storyUsers.visitor,
|
|
564
|
-
},
|
|
565
|
-
{
|
|
566
|
-
id: 'msg-2',
|
|
567
|
-
text: "That's a fine message.",
|
|
568
|
-
user: storyUsers.creator,
|
|
569
|
-
},
|
|
570
|
-
],
|
|
571
|
-
}
|
|
572
|
-
ReportOthersMessage.play = async ({ canvasElement }) => {
|
|
573
|
-
const canvas = within(canvasElement)
|
|
574
|
-
const otherBubble = await canvas.findByText('Hover me to report!')
|
|
575
|
-
await userEvent.hover(otherBubble)
|
|
576
|
-
const toggle = await canvas.findByTestId('message-actions-toggle-button')
|
|
577
|
-
await userEvent.click(toggle)
|
|
578
|
-
await expect(canvas.getByText('Report')).toBeInTheDocument()
|
|
579
|
-
}
|
|
580
|
-
ReportOthersMessage.parameters = {
|
|
581
|
-
docs: {
|
|
582
|
-
description: {
|
|
583
|
-
story:
|
|
584
|
-
"Current user hovers the other participant's message. Only \"Report\" is shown — \"Delete\" is hidden.",
|
|
585
|
-
},
|
|
586
|
-
},
|
|
587
|
-
}
|
|
@@ -85,7 +85,6 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
|
|
|
85
85
|
const {
|
|
86
86
|
Attachment = DefaultAttachment,
|
|
87
87
|
EditMessageModal = DefaultEditMessageModal,
|
|
88
|
-
MessageActions,
|
|
89
88
|
MessageBlocked = DefaultMessageBlocked,
|
|
90
89
|
MessageBouncePrompt = DefaultMessageBouncePrompt,
|
|
91
90
|
MessageDeleted = DefaultMessageDeleted,
|
|
@@ -298,28 +297,24 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
|
|
|
298
297
|
)}
|
|
299
298
|
<MessageErrorIcon />
|
|
300
299
|
</div>
|
|
300
|
+
{/* Tip/paid tags stay outside; chatbot attachment indicator stays outside too */}
|
|
301
|
+
{(!isChatbot || useAttachmentFooterChatbotTag) && (
|
|
302
|
+
<MessageTag
|
|
303
|
+
message={message}
|
|
304
|
+
hasAttachment={hasRenderableAttachments}
|
|
305
|
+
isMyMessage={isMine}
|
|
306
|
+
/>
|
|
307
|
+
)}
|
|
308
|
+
{chatbotVotingEnabled && isChatbot && (
|
|
309
|
+
<MessageVoteButtons
|
|
310
|
+
selected={voteState}
|
|
311
|
+
onVoteUp={voteUp}
|
|
312
|
+
onVoteDown={voteDown}
|
|
313
|
+
/>
|
|
314
|
+
)}
|
|
301
315
|
</div>
|
|
302
316
|
)}
|
|
303
|
-
{MessageActions && <MessageActions />}
|
|
304
317
|
</div>
|
|
305
|
-
{!isAttachment && !isTipOnly && (
|
|
306
|
-
<div className="str-chat__message-footer">
|
|
307
|
-
{(!isChatbot || useAttachmentFooterChatbotTag) && (
|
|
308
|
-
<MessageTag
|
|
309
|
-
message={message}
|
|
310
|
-
hasAttachment={hasRenderableAttachments}
|
|
311
|
-
isMyMessage={isMine}
|
|
312
|
-
/>
|
|
313
|
-
)}
|
|
314
|
-
{chatbotVotingEnabled && isChatbot && (
|
|
315
|
-
<MessageVoteButtons
|
|
316
|
-
selected={voteState}
|
|
317
|
-
onVoteUp={voteUp}
|
|
318
|
-
onVoteDown={voteDown}
|
|
319
|
-
/>
|
|
320
|
-
)}
|
|
321
|
-
</div>
|
|
322
|
-
)}
|
|
323
318
|
{showReplyCountButton && (
|
|
324
319
|
<MessageRepliesCountButton
|
|
325
320
|
onClick={handleOpenThread}
|
|
@@ -35,14 +35,15 @@ const handleDismiss = () => {
|
|
|
35
35
|
/**
|
|
36
36
|
* Single image — renders inside a chat bubble with rounded corners.
|
|
37
37
|
* Composer / Sent / Received are all interactive: clicking opens the
|
|
38
|
-
* built-in `ImageViewer` lightbox
|
|
39
|
-
*
|
|
38
|
+
* built-in `ImageViewer` lightbox (full-viewport `<dialog>`, image
|
|
39
|
+
* centered at reasonable max dimensions, close + download buttons in
|
|
40
|
+
* the chrome — Escape or backdrop click also dismiss).
|
|
40
41
|
*/
|
|
41
42
|
export const Single: StoryFn = () => (
|
|
42
43
|
<StoryPage>
|
|
43
44
|
<StoryHeading
|
|
44
45
|
title="Single image"
|
|
45
|
-
description="Click any bubble to open the lightbox viewer
|
|
46
|
+
description="Click any bubble to open the lightbox viewer. The dialog centers the image at reasonable max dimensions; close with the × button, Escape, or a backdrop click. The chrome carries a download button for grabbing the image without leaving the lightbox."
|
|
46
47
|
/>
|
|
47
48
|
<StoryGrid>
|
|
48
49
|
<StoryRow
|
|
@@ -143,7 +144,9 @@ export const SingleWithText: StoryFn = () => (
|
|
|
143
144
|
* Stacked image attachments — multiple images in one bubble laid out
|
|
144
145
|
* in a 1 / 2 / 3 / 4-tile grid. Five or more collapse into a `+N`
|
|
145
146
|
* overflow tile on the bottom-right. Click any tile to open the
|
|
146
|
-
* lightbox
|
|
147
|
+
* lightbox on that specific image; the viewer becomes a carousel
|
|
148
|
+
* (prev/next chrome, ArrowLeft / ArrowRight, and a `current / total`
|
|
149
|
+
* counter) so the user can browse siblings without closing.
|
|
147
150
|
*
|
|
148
151
|
* Sent + Received only — the composer surface accepts a single image
|
|
149
152
|
* at a time, so the Composer column is intentionally blank.
|
|
@@ -152,7 +155,7 @@ export const Stacked: StoryFn = () => (
|
|
|
152
155
|
<StoryPage>
|
|
153
156
|
<StoryHeading
|
|
154
157
|
title="Stacked images"
|
|
155
|
-
description="Click any tile to open the lightbox at that index. Use
|
|
158
|
+
description="Click any tile to open the lightbox at that index. Use the prev / next chrome or ArrowLeft / ArrowRight to navigate between siblings inside the viewer. Composer column is intentionally blank — the composer accepts a single image at a time."
|
|
156
159
|
/>
|
|
157
160
|
<StoryGrid>
|
|
158
161
|
<StoryRow
|
|
@@ -21,7 +21,7 @@ export interface ImageAttachmentSharedProps extends MessageAttachmentBaseProps {
|
|
|
21
21
|
/** Single image — convenience for the most common case. */
|
|
22
22
|
src?: string
|
|
23
23
|
alt?: string
|
|
24
|
-
/** Filename
|
|
24
|
+
/** Filename used as the viewer dialog's accessible name. */
|
|
25
25
|
filename?: string
|
|
26
26
|
/**
|
|
27
27
|
* Stacked images. Takes precedence over `src` when set. Renders a
|
|
@@ -98,6 +98,12 @@ interface InternalImageRowProps extends ImageAttachmentSharedProps {
|
|
|
98
98
|
onDismiss?: () => void
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Project the bubble's `ImageItem`s onto the carousel-aware viewer's
|
|
103
|
+
* `ImageViewerItem` shape. When a shared outer `filename` is supplied
|
|
104
|
+
* for a stacked bubble, suffix `(N)` per sibling so each carousel page
|
|
105
|
+
* still gets a distinct accessible name + download default.
|
|
106
|
+
*/
|
|
101
107
|
const buildViewerItems = (
|
|
102
108
|
resolvedItems: ImageItem[],
|
|
103
109
|
filename?: string
|