@linktr.ee/messaging-react 1.38.0 → 1.40.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/index.d.ts CHANGED
@@ -58,9 +58,6 @@ export declare const ChannelList: default_2.NamedExoticComponent<ChannelListProp
58
58
  export declare interface ChannelListProps {
59
59
  onChannelSelect: (channel: Channel) => void;
60
60
  selectedChannel?: Channel;
61
- showStartConversation?: boolean;
62
- onStartConversation?: () => void;
63
- participantLabel?: string;
64
61
  className?: string;
65
62
  filters: ChannelFilters;
66
63
  /**
@@ -363,9 +360,6 @@ declare interface MessageVoteButtonsProps {
363
360
  * Messaging capabilities configuration
364
361
  */
365
362
  export declare interface MessagingCapabilities {
366
- showStartConversation?: boolean;
367
- participantSource?: ParticipantSource;
368
- participantLabel?: string;
369
363
  /**
370
364
  * Show the "Delete Conversation" button in channel info dialog.
371
365
  * Defaults to true for backward compatibility.
@@ -416,7 +410,6 @@ export declare interface MessagingShellProps extends ChannelViewPassthroughProps
416
410
  capabilities?: MessagingCapabilities;
417
411
  className?: string;
418
412
  onChannelSelect?: (channel: Channel) => void;
419
- onParticipantSelect?: (participant: Participant) => void;
420
413
  /**
421
414
  * Auto-select a conversation with this participant on mount.
422
415
  * Useful for deep-linking to a specific conversation (e.g., /messages/[accountUuid])
@@ -480,41 +473,6 @@ export declare interface Participant {
480
473
  metadata?: Record<string, unknown>;
481
474
  }
482
475
 
483
- /**
484
- * Generic participant picker component for starting conversations
485
- */
486
- export declare const ParticipantPicker: default_2.FC<ParticipantPickerProps>;
487
-
488
- /**
489
- * ParticipantPicker component props
490
- */
491
- export declare interface ParticipantPickerProps {
492
- participantSource: ParticipantSource;
493
- onSelectParticipant: (participant: Participant) => void;
494
- onClose: () => void;
495
- existingParticipantIds?: Set<string>;
496
- participantLabel?: string;
497
- searchPlaceholder?: string;
498
- className?: string;
499
- }
500
-
501
- /**
502
- * Source for loading participants (followers, team members, etc.)
503
- */
504
- export declare interface ParticipantSource {
505
- loadParticipants: (options?: {
506
- search?: string;
507
- limit?: number;
508
- cursor?: string;
509
- }) => Promise<{
510
- participants: Participant[];
511
- hasMore: boolean;
512
- nextCursor?: string;
513
- }>;
514
- totalCount?: number;
515
- loading?: boolean;
516
- }
517
-
518
476
  /**
519
477
  * Message metadata for paid messaging and chatbot flows.
520
478
  * Used to identify message types and payment status.
@@ -548,24 +506,6 @@ declare interface UseMessageVoteResult {
548
506
  */
549
507
  export declare const useMessaging: () => MessagingContextValue;
550
508
 
551
- /**
552
- * Hook for managing participant loading with search and pagination
553
- */
554
- export declare const useParticipants: (participantSource: ParticipantSource, options?: {
555
- initialSearch?: string;
556
- pageSize?: number;
557
- }) => {
558
- participants: Participant[];
559
- loading: boolean;
560
- error: string | null;
561
- searchQuery: string;
562
- hasMore: boolean;
563
- totalCount: number | undefined;
564
- loadMore: () => void;
565
- search: (query: string) => void;
566
- refresh: () => void;
567
- };
568
-
569
509
  export declare interface VisitorCardProps extends LockedAttachmentBaseProps {
570
510
  /**
571
511
  * Called when the visitor clicks Unlock on an unpaid attachment.
package/dist/index.js CHANGED
@@ -1,25 +1,23 @@
1
- import { b as e, c as t, C as i, d as n, e as o, f as r, F as g, g as M, L as m, M as l, h as u, i as c, j as h, P as d, k as v, r as C, l as L, u as P, m as k, n as p, o as A } from "./index-B_4pciGp.js";
1
+ import { b as a, c as t, C as i, d as n, e as o, f as g, F as r, g as M, L as m, M as l, h as u, i as h, j as d, k as v, r as C, l as L, u as c, m as A, n as F } from "./index-DY-3-rt4.js";
2
2
  export {
3
- e as ActionButton,
3
+ a as ActionButton,
4
4
  t as Avatar,
5
5
  i as ChannelEmptyState,
6
6
  n as ChannelList,
7
7
  o as ChannelView,
8
- r as CustomMessageProvider,
9
- g as FaqList,
8
+ g as CustomMessageProvider,
9
+ r as FaqList,
10
10
  M as FaqListItem,
11
11
  m as LockedAttachment,
12
12
  l as MediaMessage,
13
13
  u as MessageVoteButtons,
14
- c as MessagingProvider,
15
- h as MessagingShell,
16
- d as ParticipantPicker,
14
+ h as MessagingProvider,
15
+ d as MessagingShell,
17
16
  v as formatRelativeTime,
18
17
  C as resolveLinkAttachment,
19
18
  L as resolveMediaFromMessage,
20
- P as useCustomMessage,
21
- k as useMessageVote,
22
- p as useMessaging,
23
- A as useParticipants
19
+ c as useCustomMessage,
20
+ A as useMessageVote,
21
+ F as useMessaging
24
22
  };
25
23
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linktr.ee/messaging-react",
3
- "version": "1.38.0",
3
+ "version": "1.40.0",
4
4
  "description": "React messaging components built on messaging-core for web applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -35,16 +35,11 @@ const Template: StoryFn<ComponentProps> = (args) => {
35
35
  export const Default: StoryFn<ComponentProps> = Template.bind({})
36
36
  Default.args = {
37
37
  onChannelSelect: (channel) => console.log('Channel selected:', channel.id),
38
- participantLabel: 'participants',
39
38
  }
40
39
 
41
- export const WithStartConversation: StoryFn<ComponentProps> = Template.bind({})
42
- WithStartConversation.args = {
40
+ export const WithSelection: StoryFn<ComponentProps> = Template.bind({})
41
+ WithSelection.args = {
43
42
  onChannelSelect: (channel) => console.log('Channel selected:', channel.id),
44
- showStartConversation: true,
45
- onStartConversation: () => console.log('Start conversation clicked'),
46
- participantLabel: 'followers',
47
43
  }
48
44
 
49
45
 
50
-
@@ -0,0 +1,86 @@
1
+ import type { Meta, StoryFn } from '@storybook/react'
2
+ import React, { useState } from 'react'
3
+
4
+ import type { VoteSelection } from '../../hooks/useMessageVote'
5
+
6
+ import { MessageVoteButtons } from './MessageVoteButtons'
7
+
8
+ type ComponentProps = React.ComponentProps<typeof MessageVoteButtons>
9
+
10
+ const meta: Meta<ComponentProps> = {
11
+ title: 'MessageVoteButtons',
12
+ component: MessageVoteButtons,
13
+ parameters: {
14
+ layout: 'centered',
15
+ },
16
+ }
17
+ export default meta
18
+
19
+ const Template: StoryFn<ComponentProps> = (args) => (
20
+ <div className="p-12">
21
+ <MessageVoteButtons {...args} />
22
+ </div>
23
+ )
24
+
25
+ export const Unselected: StoryFn<ComponentProps> = Template.bind({})
26
+ Unselected.args = {
27
+ selected: null,
28
+ onVoteUp: () => {},
29
+ onVoteDown: () => {},
30
+ }
31
+
32
+ export const GoodResponse: StoryFn<ComponentProps> = Template.bind({})
33
+ GoodResponse.args = {
34
+ selected: 'up',
35
+ onVoteUp: () => {},
36
+ onVoteDown: () => {},
37
+ }
38
+
39
+ export const BadResponse: StoryFn<ComponentProps> = Template.bind({})
40
+ BadResponse.args = {
41
+ selected: 'down',
42
+ onVoteUp: () => {},
43
+ onVoteDown: () => {},
44
+ }
45
+
46
+ export const Interactive: StoryFn = () => {
47
+ const [selected, setSelected] = useState<VoteSelection>(null)
48
+ return (
49
+ <div className="p-12">
50
+ <MessageVoteButtons
51
+ selected={selected}
52
+ onVoteUp={() => setSelected(selected === 'up' ? null : 'up')}
53
+ onVoteDown={() => setSelected(selected === 'down' ? null : 'down')}
54
+ />
55
+ </div>
56
+ )
57
+ }
58
+
59
+ export const AllVariants: StoryFn = () => (
60
+ <div className="p-12 flex flex-col gap-6">
61
+ <div className="flex items-center gap-4">
62
+ <span className="text-sm w-32">Unselected:</span>
63
+ <MessageVoteButtons
64
+ selected={null}
65
+ onVoteUp={() => {}}
66
+ onVoteDown={() => {}}
67
+ />
68
+ </div>
69
+ <div className="flex items-center gap-4">
70
+ <span className="text-sm w-32">Good response:</span>
71
+ <MessageVoteButtons
72
+ selected="up"
73
+ onVoteUp={() => {}}
74
+ onVoteDown={() => {}}
75
+ />
76
+ </div>
77
+ <div className="flex items-center gap-4">
78
+ <span className="text-sm w-32">Bad response:</span>
79
+ <MessageVoteButtons
80
+ selected="down"
81
+ onVoteUp={() => {}}
82
+ onVoteDown={() => {}}
83
+ />
84
+ </div>
85
+ </div>
86
+ )
@@ -1,3 +1,5 @@
1
+ import { ThumbsUpIcon, ThumbsDownIcon } from '@phosphor-icons/react'
2
+ import classNames from 'classnames'
1
3
  import React from 'react'
2
4
 
3
5
  import type { VoteSelection } from '../../hooks/useMessageVote'
@@ -8,32 +10,6 @@ interface MessageVoteButtonsProps {
8
10
  onVoteDown: () => void
9
11
  }
10
12
 
11
- const ThumbUpIcon: React.FC<{ filled: boolean }> = ({ filled }) => (
12
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
13
- <path
14
- d="M4.667 7.333l2.666-6A1.333 1.333 0 018.667 2v2.667a.667.667 0 00.666.666h3.764a1.334 1.334 0 011.192 1.93l-2.333 4.666a1.333 1.333 0 01-1.193.738H4.667m0-5.334v5.334m0-5.334H2.667a1.333 1.333 0 00-1.334 1.334v2.666a1.333 1.333 0 001.334 1.334h2"
15
- stroke="currentColor"
16
- strokeWidth="1.33"
17
- strokeLinecap="round"
18
- strokeLinejoin="round"
19
- fill={filled ? 'currentColor' : 'none'}
20
- />
21
- </svg>
22
- )
23
-
24
- const ThumbDownIcon: React.FC<{ filled: boolean }> = ({ filled }) => (
25
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
26
- <path
27
- d="M11.333 8.667l-2.666 6A1.333 1.333 0 017.333 14v-2.667a.667.667 0 00-.666-.666H2.903a1.334 1.334 0 01-1.192-1.93l2.333-4.666a1.333 1.333 0 011.193-.738h6.096m0 5.334V3.333m0 5.334h2a1.333 1.333 0 001.334-1.334V4.667a1.333 1.333 0 00-1.334-1.334h-2"
28
- stroke="currentColor"
29
- strokeWidth="1.33"
30
- strokeLinecap="round"
31
- strokeLinejoin="round"
32
- fill={filled ? 'currentColor' : 'none'}
33
- />
34
- </svg>
35
- )
36
-
37
13
  export const MessageVoteButtons: React.FC<MessageVoteButtonsProps> = ({
38
14
  selected,
39
15
  onVoteUp,
@@ -42,21 +18,27 @@ export const MessageVoteButtons: React.FC<MessageVoteButtonsProps> = ({
42
18
  <div className="message-vote-buttons">
43
19
  <button
44
20
  type="button"
45
- className={`message-vote-button${selected === 'up' ? ' message-vote-button--selected' : ''} focus-ring`}
21
+ className={classNames('message-vote-button focus-ring', {
22
+ 'message-vote-button--selected': selected === 'up',
23
+ })}
46
24
  onClick={onVoteUp}
47
- aria-label="Helpful"
25
+ aria-label="Good response"
48
26
  aria-pressed={selected === 'up'}
27
+ data-tooltip="Good response"
49
28
  >
50
- <ThumbUpIcon filled={selected === 'up'} />
29
+ <ThumbsUpIcon size={16} weight={selected === 'up' ? 'fill' : 'regular'} />
51
30
  </button>
52
31
  <button
53
32
  type="button"
54
- className={`message-vote-button${selected === 'down' ? ' message-vote-button--selected' : ''} focus-ring`}
33
+ className={classNames('message-vote-button focus-ring', {
34
+ 'message-vote-button--selected': selected === 'down',
35
+ })}
55
36
  onClick={onVoteDown}
56
- aria-label="Not helpful"
37
+ aria-label="Bad response"
57
38
  aria-pressed={selected === 'down'}
39
+ data-tooltip="Bad response"
58
40
  >
59
- <ThumbDownIcon filled={selected === 'down'} />
41
+ <ThumbsDownIcon size={16} weight={selected === 'down' ? 'fill' : 'regular'} />
60
42
  </button>
61
43
  </div>
62
44
  )
@@ -3,10 +3,9 @@ import React, { useState, useCallback, useRef, useEffect } from 'react'
3
3
  import type { Channel } from 'stream-chat'
4
4
 
5
5
  import { useMessaging } from '../../hooks/useMessaging'
6
- import type { MessagingShellProps, Participant } from '../../types'
6
+ import type { MessagingShellProps } from '../../types'
7
7
  import { ChannelList } from '../ChannelList'
8
8
  import { ChannelView } from '../ChannelView'
9
- import { ParticipantPicker } from '../ParticipantPicker'
10
9
 
11
10
  import { EmptyState } from './EmptyState'
12
11
  import { ErrorState } from './ErrorState'
@@ -21,7 +20,6 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
21
20
  renderMessageInputActions,
22
21
  renderConversationFooter,
23
22
  onChannelSelect,
24
- onParticipantSelect,
25
23
  initialParticipantFilter,
26
24
  initialParticipantData,
27
25
  CustomChannelEmptyState,
@@ -57,21 +55,12 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
57
55
  const [selectedChannel, setSelectedChannel] = useState<Channel | null>(null)
58
56
  const [hasChannels, setHasChannels] = useState(false)
59
57
  const [channelsLoaded, setChannelsLoaded] = useState(false)
60
- const [_showParticipantPicker, setShowParticipantPicker] = useState(false)
61
- const [existingParticipantIds, setExistingParticipantIds] = useState<
62
- Set<string>
63
- >(new Set())
64
- const [pickerKey, _setPickerKey] = useState(0) // Key to force remount of ParticipantPicker
65
58
  const [directConversationMode, setDirectConversationMode] = useState(false)
66
59
  const [directConversationError, setDirectConversationError] = useState<
67
60
  string | null
68
61
  >(null)
69
62
 
70
- const participantPickerRef = useRef<HTMLDialogElement>(null)
71
-
72
63
  const {
73
- participantSource,
74
- participantLabel = 'participants',
75
64
  showDeleteConversation = true,
76
65
  } = capabilities
77
66
 
@@ -121,27 +110,6 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
121
110
  { limit: 100 }
122
111
  )
123
112
 
124
- const memberIds = new Set<string>()
125
- channels.forEach((channel: Channel) => {
126
- const members = channel.state.members
127
- Object.values(members).forEach((member) => {
128
- const memberId = member.user?.id
129
- if (memberId && memberId !== userId) {
130
- memberIds.add(memberId)
131
- }
132
- })
133
- })
134
-
135
- // Only update if the set contents have changed to prevent re-renders
136
- setExistingParticipantIds((prev) => {
137
- if (
138
- prev.size === memberIds.size &&
139
- [...prev].every((id) => memberIds.has(id))
140
- ) {
141
- return prev
142
- }
143
- return memberIds
144
- })
145
113
  setHasChannels(channels.length > 0)
146
114
  setChannelsLoaded(true)
147
115
  syncedRef.current = userId // Mark as synced for this user
@@ -149,7 +117,6 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
149
117
  if (debug) {
150
118
  console.log('[MessagingShell] Channels synced successfully:', {
151
119
  channelCount: channels.length,
152
- memberCount: memberIds.size,
153
120
  })
154
121
  }
155
122
  } catch (error) {
@@ -158,7 +125,7 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
158
125
  }
159
126
  }, [client, isConnected, debug])
160
127
 
161
- // Sync existing channels to track which participants we can already message
128
+ // Sync existing channels to drive empty-state behavior.
162
129
  useEffect(() => {
163
130
  if (!client || !isConnected) return
164
131
 
@@ -303,58 +270,6 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
303
270
  setSelectedChannel(null)
304
271
  }, [directConversationMode])
305
272
 
306
- const handleSelectParticipant = useCallback(
307
- async (participant: Participant) => {
308
- if (!service) return
309
-
310
- try {
311
- if (debug) {
312
- console.log(
313
- '[MessagingShell] Starting conversation with:',
314
- participant.id
315
- )
316
- }
317
-
318
- const channel = await service.startChannelWithParticipant({
319
- id: participant.id,
320
- name: participant.name,
321
- email: participant.email,
322
- phone: participant.phone,
323
- })
324
-
325
- // Show the channel
326
- try {
327
- await channel.show()
328
- } catch (error) {
329
- console.warn('[MessagingShell] Failed to unhide channel:', error)
330
- }
331
-
332
- setSelectedChannel(channel)
333
- setShowParticipantPicker(false)
334
- participantPickerRef.current?.close()
335
-
336
- onParticipantSelect?.(participant)
337
- } catch (error) {
338
- console.error('[MessagingShell] Failed to start conversation:', error)
339
- }
340
- },
341
- [service, onParticipantSelect, debug]
342
- )
343
-
344
- const handleCloseParticipantPicker = useCallback(() => {
345
- setShowParticipantPicker(false)
346
- participantPickerRef.current?.close()
347
- }, [])
348
-
349
- const handleDialogBackdropClick = useCallback(
350
- (e: React.MouseEvent<HTMLDialogElement>) => {
351
- if (e.target === participantPickerRef.current) {
352
- handleCloseParticipantPicker()
353
- }
354
- },
355
- [handleCloseParticipantPicker]
356
- )
357
-
358
273
  const handleLeaveConversation = useCallback(
359
274
  async (channel: Channel) => {
360
275
  if (debug) {
@@ -520,29 +435,6 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
520
435
  )}
521
436
  </div>
522
437
  </div>
523
-
524
- {/* Participant Picker Dialog */}
525
- {participantSource && (
526
- // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions
527
- <dialog
528
- ref={participantPickerRef}
529
- className="mes-dialog"
530
- onClick={handleDialogBackdropClick}
531
- onClose={handleCloseParticipantPicker}
532
- >
533
- <div className="h-full w-full bg-white shadow-max-elevation-light">
534
- <ParticipantPicker
535
- key={pickerKey}
536
- participantSource={participantSource}
537
- onSelectParticipant={handleSelectParticipant}
538
- onClose={handleCloseParticipantPicker}
539
- existingParticipantIds={existingParticipantIds}
540
- participantLabel={participantLabel}
541
- searchPlaceholder={`Search ${participantLabel}...`}
542
- />
543
- </div>
544
- </dialog>
545
- )}
546
438
  </div>
547
439
  )
548
440
  }
package/src/index.ts CHANGED
@@ -7,7 +7,6 @@ export { ChannelList } from './components/ChannelList'
7
7
  export { ChannelView } from './components/ChannelView'
8
8
  export { default as ActionButton } from './components/ActionButton'
9
9
  export { default as LockedAttachment } from './components/LockedAttachment'
10
- export { ParticipantPicker } from './components/ParticipantPicker'
11
10
  export { Avatar } from './components/Avatar'
12
11
  export { FaqList } from './components/FaqList'
13
12
  export { FaqListItem } from './components/FaqList/FaqListItem'
@@ -26,7 +25,6 @@ export { CustomMessageProvider } from './components/CustomMessage/context'
26
25
 
27
26
  // Hooks
28
27
  export { useMessaging } from './hooks/useMessaging'
29
- export { useParticipants } from './hooks/useParticipants'
30
28
  export { useMessageVote } from './hooks/useMessageVote'
31
29
  export { useCustomMessage } from './components/CustomMessage/context'
32
30
 
@@ -38,10 +36,8 @@ export type {
38
36
  MessagingShellProps,
39
37
  ChannelListProps,
40
38
  ChannelViewProps,
41
- ParticipantPickerProps,
42
39
  MessagingProviderProps,
43
40
  MessagingCapabilities,
44
- ParticipantSource,
45
41
  Participant,
46
42
  LockedAttachmentSource,
47
43
  } from './types'
package/src/styles.css CHANGED
@@ -280,6 +280,7 @@
280
280
  }
281
281
 
282
282
  .message-vote-button {
283
+ position: relative;
283
284
  display: flex;
284
285
  align-items: center;
285
286
  justify-content: center;
@@ -289,7 +290,7 @@
289
290
  border: none;
290
291
  border-radius: 50%;
291
292
  background-color: transparent;
292
- color: rgba(0, 0, 0, 0.35);
293
+ color: #737373;
293
294
  cursor: pointer;
294
295
  transition:
295
296
  background-color 0.15s,
@@ -297,16 +298,91 @@
297
298
  }
298
299
 
299
300
  .message-vote-button:hover {
300
- background-color: rgba(0, 0, 0, 0.06);
301
- color: rgba(0, 0, 0, 0.55);
301
+ background-color: rgba(0, 0, 0, 0.05);
302
+ color: #737373;
302
303
  }
303
304
 
304
- .message-vote-button--selected {
305
- color: rgba(0, 0, 0, 0.7);
305
+ .message-vote-button[data-tooltip]::after {
306
+ content: attr(data-tooltip);
307
+ position: absolute;
308
+ bottom: calc(100% + 6px);
309
+ left: 50%;
310
+ transform: translateX(-50%);
311
+ background-color: rgba(0, 0, 0, 0.85);
312
+ color: #fff;
313
+ font-size: 12px;
314
+ line-height: 1;
315
+ padding: 4px 8px;
316
+ border-radius: 4px;
317
+ white-space: nowrap;
318
+ pointer-events: none;
319
+ opacity: 0;
320
+ transition: opacity 0.15s 0s;
306
321
  }
307
322
 
308
- .message-vote-button--selected:hover {
309
- color: rgba(0, 0, 0, 0.7);
323
+ .message-vote-button[data-tooltip]:hover::after,
324
+ .message-vote-button[data-tooltip]:focus-visible::after {
325
+ opacity: 1;
326
+ transition-delay: 300ms;
327
+ }
328
+
329
+ /* Chatbot reply markdown — restore semantics that consumer Tailwind preflight
330
+ (or other resets) strip from the body of `.str-chat__message-text-inner`. */
331
+ .str-chat__message-text-inner :where(h1, h2, h3, h4, h5, h6) {
332
+ font-weight: 600;
333
+ margin: 0.5rem 0 0.25rem;
334
+ line-height: 1.3;
335
+ text-wrap: balance;
336
+ }
337
+ .str-chat__message-text-inner h1 {
338
+ font-size: 1.5rem;
339
+ }
340
+ .str-chat__message-text-inner h2 {
341
+ font-size: 1.25rem;
342
+ }
343
+ .str-chat__message-text-inner h3 {
344
+ font-size: 1.0625rem;
345
+ }
346
+ .str-chat__message-text-inner :where(h1, h2, h3, h4, h5, h6):first-child {
347
+ margin-top: 0;
348
+ }
349
+
350
+ .str-chat__message-text-inner ul {
351
+ list-style-type: disc;
352
+ padding-inline-start: 1.25rem;
353
+ margin: 0.25rem 0;
354
+ }
355
+ .str-chat__message-text-inner ol {
356
+ list-style-type: decimal;
357
+ padding-inline-start: 1.25rem;
358
+ margin: 0.25rem 0;
359
+ }
360
+ .str-chat__message-text-inner li {
361
+ display: list-item;
362
+ margin: 0.125rem 0;
363
+ }
364
+ .str-chat__message-text-inner ul ul,
365
+ .str-chat__message-text-inner ol ol,
366
+ .str-chat__message-text-inner ul ol,
367
+ .str-chat__message-text-inner ol ul {
368
+ margin: 0;
369
+ }
370
+
371
+ .str-chat__message-text-inner a {
372
+ text-decoration: underline;
373
+ text-underline-offset: 0.15em;
374
+ word-break: break-word;
375
+ }
376
+
377
+ .str-chat__message-text-inner p {
378
+ margin: 0.25rem 0;
379
+ text-wrap: pretty;
380
+ }
381
+ .str-chat__message-text-inner > :first-child {
382
+ margin-top: 0;
383
+ }
384
+ .str-chat__message-text-inner > :last-child {
385
+ margin-bottom: 0;
310
386
  }
311
387
 
312
388
  /* Standalone tip message (tip without text) */