@linktr.ee/messaging-react 3.37.1 → 3.38.0-rc-1786343622
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-DVMzYquF.js → Card-D2RldKU0.js} +2 -2
- package/dist/{Card-DVMzYquF.js.map → Card-D2RldKU0.js.map} +1 -1
- package/dist/{Card-Dxk_Ggxw.cjs → Card-OtystGRA.cjs} +2 -2
- package/dist/{Card-Dxk_Ggxw.cjs.map → Card-OtystGRA.cjs.map} +1 -1
- package/dist/assets/index.css +1 -1
- package/dist/{index-BOBIiAuD.js → index-BoxX5w8R.js} +3123 -3163
- package/dist/index-BoxX5w8R.js.map +1 -0
- package/dist/index-BrZetD5p.cjs +3 -0
- package/dist/index-BrZetD5p.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -34
- package/dist/index.js +27 -29
- package/package.json +4 -3
- package/src/components/ChannelView.tsx +1 -6
- package/src/components/CustomMessage/CustomMessage.test.tsx +0 -12
- package/src/components/CustomMessage/MessageTag.test.tsx +9 -18
- package/src/components/CustomMessage/MessageTag.tsx +16 -17
- package/src/components/CustomMessage/MessageTail.tsx +45 -0
- package/src/components/CustomMessage/SentMessageDeliveryStatus.tsx +9 -2
- package/src/components/CustomMessage/StreamAttachmentMessage.tsx +18 -4
- package/src/components/CustomMessage/index.tsx +32 -24
- package/src/components/LinkAttachment/components/_shared/BubbleTail.tsx +5 -6
- package/src/components/MessageAttachment/_shared/CarouselNav.tsx +5 -6
- package/src/components/MessageAttachment/_shared/DownloadAction.tsx +5 -8
- package/src/components/MessageAttachment/_shared/ImageViewer.tsx +8 -12
- package/src/components/MessageAttachment/_shared/PdfViewer.tsx +1 -1
- package/src/components/MessageAttachment/_shared/VideoViewer.tsx +1 -1
- package/src/components/MessageAttachment/_shared/ViewerShell.tsx +16 -11
- package/src/components/MessageAttachment/_shared/viewerChromeClasses.ts +16 -0
- package/src/components/MessagingShell/index.tsx +0 -2
- package/src/index.ts +0 -3
- package/src/styles.css +56 -377
- package/src/types.ts +0 -8
- package/dist/index-BOBIiAuD.js.map +0 -1
- package/dist/index-D7A8U8GQ.cjs +0 -3
- package/dist/index-D7A8U8GQ.cjs.map +0 -1
- package/src/components/CustomMessage/MessageVoteButtons.stories.tsx +0 -95
- package/src/components/CustomMessage/MessageVoteButtons.tsx +0 -47
- package/src/hooks/useMessageVote.ts +0 -77
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { CaretLeftIcon, CaretRightIcon } from '@phosphor-icons/react'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
|
|
4
|
+
import { VIEWER_NAV_CLASS } from './viewerChromeClasses'
|
|
5
|
+
|
|
4
6
|
export interface CarouselNavProps {
|
|
5
7
|
onPrev: () => void
|
|
6
8
|
onNext: () => void
|
|
@@ -13,10 +15,7 @@ export interface CarouselNavProps {
|
|
|
13
15
|
/**
|
|
14
16
|
* Prev / next chrome shared by every carousel-aware viewer. Rendered
|
|
15
17
|
* inside the dialog body so the buttons sit absolutely positioned
|
|
16
|
-
* against the viewer
|
|
17
|
-
*
|
|
18
|
-
* Styling lives as plain CSS in `styles.css` so the buttons render
|
|
19
|
-
* correctly regardless of whether the consumer has Tailwind wired up.
|
|
18
|
+
* against the viewer, mid-height on each edge.
|
|
20
19
|
*/
|
|
21
20
|
const CarouselNav: React.FC<CarouselNavProps> = ({
|
|
22
21
|
onPrev,
|
|
@@ -29,7 +28,7 @@ const CarouselNav: React.FC<CarouselNavProps> = ({
|
|
|
29
28
|
type="button"
|
|
30
29
|
onClick={onPrev}
|
|
31
30
|
aria-label={prevLabel}
|
|
32
|
-
className=
|
|
31
|
+
className={`${VIEWER_NAV_CLASS} left-4`}
|
|
33
32
|
>
|
|
34
33
|
<CaretLeftIcon size={20} weight="bold" aria-hidden />
|
|
35
34
|
</button>
|
|
@@ -37,7 +36,7 @@ const CarouselNav: React.FC<CarouselNavProps> = ({
|
|
|
37
36
|
type="button"
|
|
38
37
|
onClick={onNext}
|
|
39
38
|
aria-label={nextLabel}
|
|
40
|
-
className=
|
|
39
|
+
className={`${VIEWER_NAV_CLASS} right-4`}
|
|
41
40
|
>
|
|
42
41
|
<CaretRightIcon size={20} weight="bold" aria-hidden />
|
|
43
42
|
</button>
|
|
@@ -7,6 +7,7 @@ import classNames from 'classnames'
|
|
|
7
7
|
import React, { useCallback, useState } from 'react'
|
|
8
8
|
|
|
9
9
|
import { triggerDownload } from './triggerDownload'
|
|
10
|
+
import { VIEWER_ACTION_CLASS } from './viewerChromeClasses'
|
|
10
11
|
|
|
11
12
|
export type DownloadActionVariant =
|
|
12
13
|
/** Solid pill button used inside compact / file rows. */
|
|
@@ -20,9 +21,7 @@ export type DownloadActionVariant =
|
|
|
20
21
|
/**
|
|
21
22
|
* Round icon button sized to match the close action in the
|
|
22
23
|
* `ViewerShell` chrome — used by `ImageViewer` for in-viewer
|
|
23
|
-
* downloads.
|
|
24
|
-
* it renders correctly without a Tailwind dependency in the
|
|
25
|
-
* consumer's app.
|
|
24
|
+
* downloads. Shares `VIEWER_ACTION_CLASS` with the close button.
|
|
26
25
|
*/
|
|
27
26
|
| 'viewer'
|
|
28
27
|
|
|
@@ -123,17 +122,15 @@ const DownloadAction: React.FC<DownloadActionProps> = ({
|
|
|
123
122
|
}
|
|
124
123
|
|
|
125
124
|
if (variant === 'viewer') {
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
// outside this repo without a Tailwind setup. Sits next to the
|
|
129
|
-
// close action inside `ViewerShell`'s top-right chrome.
|
|
125
|
+
// Sits next to the close action inside `ViewerShell`'s top-right chrome
|
|
126
|
+
// and shares its circular-button styling via `VIEWER_ACTION_CLASS`.
|
|
130
127
|
return (
|
|
131
128
|
<button
|
|
132
129
|
type="button"
|
|
133
130
|
onClick={handleClick}
|
|
134
131
|
disabled={busy}
|
|
135
132
|
aria-label={label}
|
|
136
|
-
className=
|
|
133
|
+
className={VIEWER_ACTION_CLASS}
|
|
137
134
|
>
|
|
138
135
|
{busy ? (
|
|
139
136
|
<CircleNotchIcon size={20} weight="bold" aria-hidden />
|
|
@@ -88,19 +88,15 @@ const ImageViewer: React.FC<ImageViewerProps> = ({
|
|
|
88
88
|
src={item.src}
|
|
89
89
|
alt={item.alt ?? filename}
|
|
90
90
|
draggable={false}
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
// full-resolution original — note the viewer intentionally
|
|
99
|
-
// uses the raw `item.src`, not the CDN-optimised URL the
|
|
100
|
-
// bubble tile renders.
|
|
101
|
-
loading="eager"
|
|
91
|
+
// Gated on `open` (see the `{open ? … : null}` above): `ViewerShell`
|
|
92
|
+
// keeps its `<dialog>` mounted across open/close so the platform
|
|
93
|
+
// transition can play, but a mounted-closed dialog would still hold
|
|
94
|
+
// this `<img>` in the DOM. The viewer uses the raw `item.src` — the
|
|
95
|
+
// full-resolution original, not the CDN-optimised URL the bubble tile
|
|
96
|
+
// renders — so rendering it unconditionally made every image in a
|
|
97
|
+
// thread prefetch its full-res original. Only mount it while open.
|
|
102
98
|
decoding="async"
|
|
103
|
-
className="
|
|
99
|
+
className="block h-auto max-h-[calc(100dvh-128px)] w-auto max-w-[min(96vw,1400px)] select-none object-contain"
|
|
104
100
|
/>
|
|
105
101
|
) : null}
|
|
106
102
|
|
|
@@ -76,7 +76,7 @@ const PdfViewer: React.FC<PdfViewerProps> = ({
|
|
|
76
76
|
key={`${index}:${item.src}`}
|
|
77
77
|
src={iframeSrc}
|
|
78
78
|
title={filename}
|
|
79
|
-
className="
|
|
79
|
+
className="block h-[calc(100dvh-128px)] w-[min(96vw,1400px)] border-0 bg-white"
|
|
80
80
|
// Sandbox the iframe to stop the embedded document from
|
|
81
81
|
// reaching parent context. We intentionally omit
|
|
82
82
|
// `allow-same-origin`: even when the PDF host happens to share
|
|
@@ -92,7 +92,7 @@ const VideoViewer: React.FC<VideoViewerProps> = ({
|
|
|
92
92
|
muted
|
|
93
93
|
playsInline
|
|
94
94
|
preload={item.preload ?? 'metadata'}
|
|
95
|
-
className="
|
|
95
|
+
className="block h-auto max-h-[calc(100dvh-128px)] w-auto max-w-[min(96vw,1400px)] bg-black"
|
|
96
96
|
>
|
|
97
97
|
{item.mimeType ? <source src={item.src} type={item.mimeType} /> : null}
|
|
98
98
|
</video>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { XIcon } from '@phosphor-icons/react'
|
|
2
2
|
import React, { useEffect, useRef } from 'react'
|
|
3
3
|
|
|
4
|
+
import { VIEWER_ACTION_CLASS } from './viewerChromeClasses'
|
|
5
|
+
|
|
4
6
|
export interface ViewerShellProps {
|
|
5
7
|
open: boolean
|
|
6
8
|
onClose: () => void
|
|
@@ -20,8 +22,7 @@ export interface ViewerShellProps {
|
|
|
20
22
|
counter?: React.ReactNode
|
|
21
23
|
/**
|
|
22
24
|
* Extra buttons rendered alongside the close button in the top-right
|
|
23
|
-
* chrome (e.g. a download action)
|
|
24
|
-
* styling so the row reads as one consistent button group.
|
|
25
|
+
* chrome (e.g. a download action), laid out as one consistent button group.
|
|
25
26
|
*/
|
|
26
27
|
actions?: React.ReactNode
|
|
27
28
|
children: React.ReactNode
|
|
@@ -40,10 +41,10 @@ export interface ViewerShellProps {
|
|
|
40
41
|
* fallback for environments where `showModal` is unavailable
|
|
41
42
|
* (jsdom under tests).
|
|
42
43
|
*
|
|
43
|
-
* The
|
|
44
|
-
*
|
|
45
|
-
* `@
|
|
46
|
-
*
|
|
44
|
+
* The `<dialog>` root, backdrop, and open/close transitions live in
|
|
45
|
+
* `styles.css` under `.mes-media-viewer` (they use `::backdrop` /
|
|
46
|
+
* `@starting-style`, which Tailwind can't express). The chrome inside is
|
|
47
|
+
* plain Tailwind on the JSX, like the rest of the package.
|
|
47
48
|
*/
|
|
48
49
|
const ViewerShell: React.FC<ViewerShellProps> = ({
|
|
49
50
|
open,
|
|
@@ -154,24 +155,28 @@ const ViewerShell: React.FC<ViewerShellProps> = ({
|
|
|
154
155
|
onClose={handleDialogClose}
|
|
155
156
|
onClick={handleDialogClick}
|
|
156
157
|
>
|
|
157
|
-
<div className="
|
|
158
|
+
<div className="pointer-events-none absolute inset-x-3 top-3 z-[1] flex items-center justify-between gap-3">
|
|
158
159
|
{counter ? (
|
|
159
|
-
<span className="
|
|
160
|
+
<span className="pointer-events-auto inline-flex items-center rounded-full bg-white/[0.12] px-3 py-1.5 text-[13px] font-medium leading-none tabular-nums text-white">
|
|
161
|
+
{counter}
|
|
162
|
+
</span>
|
|
160
163
|
) : null}
|
|
161
|
-
<div className="
|
|
164
|
+
<div className="pointer-events-auto ml-auto inline-flex items-center gap-2">
|
|
162
165
|
{actions}
|
|
163
166
|
<button
|
|
164
167
|
ref={closeButtonRef}
|
|
165
168
|
type="button"
|
|
166
169
|
onClick={onClose}
|
|
167
170
|
aria-label="Close viewer"
|
|
168
|
-
className=
|
|
171
|
+
className={VIEWER_ACTION_CLASS}
|
|
169
172
|
>
|
|
170
173
|
<XIcon size={20} weight="bold" aria-hidden />
|
|
171
174
|
</button>
|
|
172
175
|
</div>
|
|
173
176
|
</div>
|
|
174
|
-
<div className="
|
|
177
|
+
<div className="box-border flex h-full w-full items-center justify-center px-6 py-16">
|
|
178
|
+
{children}
|
|
179
|
+
</div>
|
|
175
180
|
</dialog>
|
|
176
181
|
)
|
|
177
182
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Tailwind class strings for the media-viewer chrome buttons, reused by
|
|
3
|
+
* `ViewerShell` (close), `DownloadAction`, and `CarouselNav` so every
|
|
4
|
+
* viewer-chrome button stays visually consistent without duplicating the
|
|
5
|
+
* utility list. The lightbox `<dialog>` root itself still lives in
|
|
6
|
+
* `styles.css` (`.mes-media-viewer`) because `::backdrop` / `@starting-style`
|
|
7
|
+
* can't be expressed in Tailwind.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Circular 40px icon button — close action, download action, etc. */
|
|
11
|
+
export const VIEWER_ACTION_CLASS =
|
|
12
|
+
'inline-flex size-10 items-center justify-center rounded-full border-0 bg-white/[0.12] p-0 text-white transition-colors duration-150 ease-[ease] hover:bg-white/[0.22] focus-visible:bg-white/[0.22] focus-visible:outline-none disabled:cursor-default disabled:opacity-40'
|
|
13
|
+
|
|
14
|
+
/** Circular 48px carousel prev/next button, mid-height against the dialog. */
|
|
15
|
+
export const VIEWER_NAV_CLASS =
|
|
16
|
+
'absolute top-1/2 z-[1] inline-flex size-12 -translate-y-1/2 items-center justify-center rounded-full border-0 bg-white/[0.12] p-0 text-white transition-colors duration-150 ease-[ease] hover:bg-white/[0.22] focus-visible:bg-white/[0.22] focus-visible:outline-none'
|
|
@@ -32,7 +32,6 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
|
|
|
32
32
|
onReportParticipantClick,
|
|
33
33
|
dmAgentEnabled,
|
|
34
34
|
onMessageSent,
|
|
35
|
-
chatbotVotingEnabled = false,
|
|
36
35
|
viewerLanguage,
|
|
37
36
|
renderChannelBanner,
|
|
38
37
|
customChannelActions,
|
|
@@ -260,7 +259,6 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
|
|
|
260
259
|
onReportParticipantClick={onReportParticipantClick}
|
|
261
260
|
dmAgentEnabled={dmAgentEnabled}
|
|
262
261
|
onMessageSent={onMessageSent}
|
|
263
|
-
chatbotVotingEnabled={chatbotVotingEnabled}
|
|
264
262
|
viewerLanguage={viewerLanguage}
|
|
265
263
|
customChannelActions={customChannelActions}
|
|
266
264
|
renderChannelActions={renderChannelActions}
|
package/src/index.ts
CHANGED
|
@@ -15,7 +15,6 @@ export { default as MessageBubble } from './components/MessageBubble'
|
|
|
15
15
|
export { FaqList } from './components/FaqList'
|
|
16
16
|
export { FaqListItem } from './components/FaqList/FaqListItem'
|
|
17
17
|
export { ChannelEmptyState } from './components/MessagingShell/ChannelEmptyState'
|
|
18
|
-
export { MessageVoteButtons } from './components/CustomMessage/MessageVoteButtons'
|
|
19
18
|
export {
|
|
20
19
|
MediaMessage,
|
|
21
20
|
isLinkAttachment,
|
|
@@ -34,7 +33,6 @@ export { CustomMessageProvider } from './components/CustomMessage/context'
|
|
|
34
33
|
// Hooks
|
|
35
34
|
export { useComposerLocked } from './components/CustomMessageInput'
|
|
36
35
|
export { useMessaging } from './hooks/useMessaging'
|
|
37
|
-
export { useMessageVote } from './hooks/useMessageVote'
|
|
38
36
|
export { useCustomMessage } from './components/CustomMessage/context'
|
|
39
37
|
|
|
40
38
|
// Utils
|
|
@@ -136,4 +134,3 @@ export type { CustomMessageRegistry } from './components/CustomMessage/context'
|
|
|
136
134
|
export type { AttachmentSourceType } from './components/AttachmentCard/utils/mimeType'
|
|
137
135
|
export type { Faq, FaqListProps } from './components/FaqList'
|
|
138
136
|
export type { FaqListItemProps } from './components/FaqList/FaqListItem'
|
|
139
|
-
export type { VoteSelection } from './hooks/useMessageVote'
|