@linktr.ee/messaging-react 3.15.0 → 3.15.1-rc-1784866707

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.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-NcnnPWrl.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.MessageBubble=e.MessageBubble;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.optimizeMessagingAttachmentUrl=e.optimizeMessagingAttachmentUrl;exports.resolveConversationParticipant=e.resolveConversationParticipant;exports.resolveLinkAttachment=e.resolveLinkAttachment;exports.resolveMediaFromMessage=e.resolveMediaFromMessage;exports.resolveParticipantDisplayName=e.resolveParticipantDisplayName;exports.useComposerLocked=e.useComposerLocked;exports.useCustomMessage=e.useCustomMessage;exports.useMessageVote=e.useMessageVote;exports.useMessaging=e.useMessaging;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-stv1fd7v.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.MessageBubble=e.MessageBubble;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.optimizeMessagingAttachmentUrl=e.optimizeMessagingAttachmentUrl;exports.resolveConversationParticipant=e.resolveConversationParticipant;exports.resolveLinkAttachment=e.resolveLinkAttachment;exports.resolveMediaFromMessage=e.resolveMediaFromMessage;exports.resolveParticipantDisplayName=e.resolveParticipantDisplayName;exports.useComposerLocked=e.useComposerLocked;exports.useCustomMessage=e.useCustomMessage;exports.useMessageVote=e.useMessageVote;exports.useMessaging=e.useMessaging;
2
2
  //# sourceMappingURL=index.cjs.map
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as e, b as t, C as i, c as o, d as n, e as m, F as r, f as g, L as l, h as M, M as c, i as u, j as L, k as h, l as p, m as d, n as v, p as C, q as A, s as k, t as F, u as b, v as P, w as f, x, o as y, y as z, z as B, B as S, D as q, E as D, G as E, H as V, I as w } from "./index-DdVzOymJ.js";
1
+ import { a as e, b as t, C as i, c as o, d as n, e as m, F as r, f as g, L as l, h as M, M as c, i as u, j as L, k as h, l as p, m as d, n as v, p as C, q as A, s as k, t as F, u as b, v as P, w as f, x, o as y, y as z, z as B, B as S, D as q, E as D, G as E, H as V, I as w } from "./index-BOThiuy9.js";
2
2
  export {
3
3
  e as ActionButton,
4
4
  t as Avatar,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linktr.ee/messaging-react",
3
- "version": "3.15.0",
3
+ "version": "3.15.1-rc-1784866707",
4
4
  "description": "React messaging components built on messaging-core for web applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "@linktr.ee/component-library": "11.8.6",
53
- "@linktr.ee/messaging-core": "^2.2.0",
53
+ "@linktr.ee/messaging-core": "2.3.0-rc-1784866707",
54
54
  "@phosphor-icons/react": "^2.1.10"
55
55
  },
56
56
  "devDependencies": {
@@ -11,6 +11,7 @@ import {
11
11
  useMessageInputContext,
12
12
  } from 'stream-chat-react'
13
13
 
14
+ import { isIOS } from '../../utils/isIOS'
14
15
  import { CustomLinkPreviewList } from '../CustomLinkPreviewList'
15
16
 
16
17
  /**
@@ -33,6 +34,10 @@ const ComposerLockedContext = React.createContext(false)
33
34
  */
34
35
  const NEAR_BOTTOM_THRESHOLD_PX = 200
35
36
 
37
+ // Read once: the user agent doesn't change over a session, so there's no
38
+ // reason to re-run the check on every render.
39
+ const IS_IOS = isIOS()
40
+
36
41
  /**
37
42
  * Read the composer's locked (frozen-channel) state from inside a custom
38
43
  * composer supplied via `composerInput`. Returns true when the channel is
@@ -119,9 +124,13 @@ const CustomMessageInputInner: React.FC = () => {
119
124
  className="w-full resize-none bg-transparent py-3.5 pl-4 pr-4 outline-none leading-5 placeholder:text-black/30 text-sm"
120
125
  // While this might usually be considered an anti-pattern, in most
121
126
  // cases, when a message thread is rendered, we want the input to
122
- // gain focus automatically.
127
+ // gain focus automatically. Skipped on iOS: WebKit only opens the
128
+ // keyboard for a focus() made inside a genuine user gesture, so
129
+ // autofocusing on mount just flashes focus (enough to trip a
130
+ // host's focus-driven viewport resize) before WebKit revokes it —
131
+ // net worse than waiting for the user's first tap.
123
132
  // eslint-disable-next-line jsx-a11y/no-autofocus
124
- autoFocus={!disabled}
133
+ autoFocus={!disabled && !IS_IOS}
125
134
  // Enter sends (Shift+Enter inserts a newline), so label the
126
135
  // on-screen keyboard's return key accordingly.
127
136
  enterKeyHint="send"
@@ -0,0 +1,54 @@
1
+ import { afterEach, describe, expect, it, vi } from 'vitest'
2
+
3
+ import { isIOS } from './isIOS'
4
+
5
+ const mockNavigator = (overrides: Partial<Navigator>) => {
6
+ vi.stubGlobal('navigator', { ...navigator, ...overrides })
7
+ }
8
+
9
+ describe('isIOS', () => {
10
+ afterEach(() => {
11
+ vi.unstubAllGlobals()
12
+ })
13
+
14
+ it('detects iPhone user agents', () => {
15
+ mockNavigator({
16
+ userAgent:
17
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15',
18
+ })
19
+
20
+ expect(isIOS()).toBe(true)
21
+ })
22
+
23
+ it('detects iPadOS, which reports as MacIntel but exposes touch points', () => {
24
+ mockNavigator({
25
+ userAgent:
26
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15',
27
+ platform: 'MacIntel',
28
+ maxTouchPoints: 5,
29
+ })
30
+
31
+ expect(isIOS()).toBe(true)
32
+ })
33
+
34
+ it('does not flag a real Mac (no touch points)', () => {
35
+ mockNavigator({
36
+ userAgent:
37
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15',
38
+ platform: 'MacIntel',
39
+ maxTouchPoints: 0,
40
+ })
41
+
42
+ expect(isIOS()).toBe(false)
43
+ })
44
+
45
+ it('does not flag Android', () => {
46
+ mockNavigator({
47
+ userAgent: 'Mozilla/5.0 (Linux; Android 14) AppleWebKit/537.36',
48
+ platform: 'Linux armv81',
49
+ maxTouchPoints: 5,
50
+ })
51
+
52
+ expect(isIOS()).toBe(false)
53
+ })
54
+ })
@@ -0,0 +1,19 @@
1
+ /**
2
+ * True on iOS (including iPadOS, which reports as `MacIntel` but exposes
3
+ * touch points a real Mac never does). WebKit only opens the on-screen
4
+ * keyboard for a `focus()` call made inside a genuine user gesture — an
5
+ * `autoFocus`/programmatic focus on mount briefly flashes focus (enough to
6
+ * trip a host's focus-driven viewport resize) before WebKit revokes it, so
7
+ * callers use this to skip autofocusing the composer on iOS and let the
8
+ * user's first tap focus it instead.
9
+ */
10
+ export function isIOS(): boolean {
11
+ if (typeof navigator === 'undefined') {
12
+ return false
13
+ }
14
+
15
+ return (
16
+ /iPad|iPhone|iPod/.test(navigator.userAgent) ||
17
+ (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)
18
+ )
19
+ }