@droppii-org/chat-mobile 0.2.105 → 0.2.107

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.
Files changed (152) hide show
  1. package/lib/module/components/TypingDots/TypingDots.js +131 -0
  2. package/lib/module/components/TypingDots/TypingDots.js.map +1 -0
  3. package/lib/module/components/TypingDots/index.js +4 -0
  4. package/lib/module/components/TypingDots/index.js.map +1 -0
  5. package/lib/module/components/messages/ExpandableMessageText.js +112 -0
  6. package/lib/module/components/messages/ExpandableMessageText.js.map +1 -0
  7. package/lib/module/components/messages/PreviewScrollableText.js +80 -0
  8. package/lib/module/components/messages/PreviewScrollableText.js.map +1 -0
  9. package/lib/module/components/messages/linkMessage/index.js +21 -12
  10. package/lib/module/components/messages/linkMessage/index.js.map +1 -1
  11. package/lib/module/components/messages/quotedMessage/index.js +12 -2
  12. package/lib/module/components/messages/quotedMessage/index.js.map +1 -1
  13. package/lib/module/components/messages/textMessage/index.js +7 -1
  14. package/lib/module/components/messages/textMessage/index.js.map +1 -1
  15. package/lib/module/components/messages/types.js.map +1 -1
  16. package/lib/module/core/useChatListener.js +26 -2
  17. package/lib/module/core/useChatListener.js.map +1 -1
  18. package/lib/module/hooks/groups/useGroupMemberName.js +32 -0
  19. package/lib/module/hooks/groups/useGroupMemberName.js.map +1 -0
  20. package/lib/module/hooks/query-keys.js +2 -1
  21. package/lib/module/hooks/query-keys.js.map +1 -1
  22. package/lib/module/hooks/useExpandableText.js +120 -0
  23. package/lib/module/hooks/useExpandableText.js.map +1 -0
  24. package/lib/module/hooks/useInputState.js +38 -0
  25. package/lib/module/hooks/useInputState.js.map +1 -0
  26. package/lib/module/hooks/useInputStateBroadcast.js +53 -0
  27. package/lib/module/hooks/useInputStateBroadcast.js.map +1 -0
  28. package/lib/module/screens/chat-detail/ChatComposer.js +15 -3
  29. package/lib/module/screens/chat-detail/ChatComposer.js.map +1 -1
  30. package/lib/module/screens/chat-detail/ChatDetail.js +11 -0
  31. package/lib/module/screens/chat-detail/ChatDetail.js.map +1 -1
  32. package/lib/module/screens/chat-detail/ChatListLegend.js +2 -1
  33. package/lib/module/screens/chat-detail/ChatListLegend.js.map +1 -1
  34. package/lib/module/screens/chat-detail/ChatTypingIndicator.js +86 -0
  35. package/lib/module/screens/chat-detail/ChatTypingIndicator.js.map +1 -0
  36. package/lib/module/screens/chat-detail/PinnedMessagesSheet.js +7 -0
  37. package/lib/module/screens/chat-detail/PinnedMessagesSheet.js.map +1 -1
  38. package/lib/module/screens/chat-detail/legend/LegendChatMessage.js +10 -3
  39. package/lib/module/screens/chat-detail/legend/LegendChatMessage.js.map +1 -1
  40. package/lib/module/screens/chat-detail/messageToolbox/MessageToolboxOverlay.js +11 -2
  41. package/lib/module/screens/chat-detail/messageToolbox/MessageToolboxOverlay.js.map +1 -1
  42. package/lib/module/screens/chat-detail/messageToolbox/MessageToolboxWrapper.js +79 -6
  43. package/lib/module/screens/chat-detail/messageToolbox/MessageToolboxWrapper.js.map +1 -1
  44. package/lib/module/screens/chat-detail/messageToolbox/useClonePreview.js +30 -0
  45. package/lib/module/screens/chat-detail/messageToolbox/useClonePreview.js.map +1 -0
  46. package/lib/module/store/expandedMessage.js +28 -0
  47. package/lib/module/store/expandedMessage.js.map +1 -0
  48. package/lib/module/store/index.js +1 -0
  49. package/lib/module/store/index.js.map +1 -1
  50. package/lib/module/store/inputState.js +64 -0
  51. package/lib/module/store/inputState.js.map +1 -0
  52. package/lib/module/translation/resources/i18n.js +2 -0
  53. package/lib/module/translation/resources/i18n.js.map +1 -1
  54. package/lib/module/utils/expandableText.js +41 -0
  55. package/lib/module/utils/expandableText.js.map +1 -0
  56. package/lib/module/utils/inlineTruncation.js +51 -0
  57. package/lib/module/utils/inlineTruncation.js.map +1 -0
  58. package/lib/module/utils/inputState.js +77 -0
  59. package/lib/module/utils/inputState.js.map +1 -0
  60. package/lib/module/utils/message.js +9 -0
  61. package/lib/module/utils/message.js.map +1 -1
  62. package/lib/module/utils/truncateTextChildren.js +38 -0
  63. package/lib/module/utils/truncateTextChildren.js.map +1 -0
  64. package/lib/typescript/src/components/TypingDots/TypingDots.d.ts +14 -0
  65. package/lib/typescript/src/components/TypingDots/TypingDots.d.ts.map +1 -0
  66. package/lib/typescript/src/components/TypingDots/index.d.ts +3 -0
  67. package/lib/typescript/src/components/TypingDots/index.d.ts.map +1 -0
  68. package/lib/typescript/src/components/messages/ExpandableMessageText.d.ts +25 -0
  69. package/lib/typescript/src/components/messages/ExpandableMessageText.d.ts.map +1 -0
  70. package/lib/typescript/src/components/messages/PreviewScrollableText.d.ts +29 -0
  71. package/lib/typescript/src/components/messages/PreviewScrollableText.d.ts.map +1 -0
  72. package/lib/typescript/src/components/messages/linkMessage/index.d.ts +1 -1
  73. package/lib/typescript/src/components/messages/linkMessage/index.d.ts.map +1 -1
  74. package/lib/typescript/src/components/messages/quotedMessage/index.d.ts.map +1 -1
  75. package/lib/typescript/src/components/messages/textMessage/index.d.ts +1 -1
  76. package/lib/typescript/src/components/messages/textMessage/index.d.ts.map +1 -1
  77. package/lib/typescript/src/components/messages/types.d.ts +18 -0
  78. package/lib/typescript/src/components/messages/types.d.ts.map +1 -1
  79. package/lib/typescript/src/core/useChatListener.d.ts.map +1 -1
  80. package/lib/typescript/src/hooks/groups/useGroupMemberName.d.ts +10 -0
  81. package/lib/typescript/src/hooks/groups/useGroupMemberName.d.ts.map +1 -0
  82. package/lib/typescript/src/hooks/query-keys.d.ts +1 -0
  83. package/lib/typescript/src/hooks/query-keys.d.ts.map +1 -1
  84. package/lib/typescript/src/hooks/useExpandableText.d.ts +13 -0
  85. package/lib/typescript/src/hooks/useExpandableText.d.ts.map +1 -0
  86. package/lib/typescript/src/hooks/useInputState.d.ts +21 -0
  87. package/lib/typescript/src/hooks/useInputState.d.ts.map +1 -0
  88. package/lib/typescript/src/hooks/useInputStateBroadcast.d.ts +14 -0
  89. package/lib/typescript/src/hooks/useInputStateBroadcast.d.ts.map +1 -0
  90. package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts.map +1 -1
  91. package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts.map +1 -1
  92. package/lib/typescript/src/screens/chat-detail/ChatListLegend.d.ts.map +1 -1
  93. package/lib/typescript/src/screens/chat-detail/ChatTypingIndicator.d.ts +8 -0
  94. package/lib/typescript/src/screens/chat-detail/ChatTypingIndicator.d.ts.map +1 -0
  95. package/lib/typescript/src/screens/chat-detail/PinnedMessagesSheet.d.ts.map +1 -1
  96. package/lib/typescript/src/screens/chat-detail/legend/LegendChatMessage.d.ts +11 -1
  97. package/lib/typescript/src/screens/chat-detail/legend/LegendChatMessage.d.ts.map +1 -1
  98. package/lib/typescript/src/screens/chat-detail/messageToolbox/MessageToolboxOverlay.d.ts.map +1 -1
  99. package/lib/typescript/src/screens/chat-detail/messageToolbox/MessageToolboxWrapper.d.ts +14 -1
  100. package/lib/typescript/src/screens/chat-detail/messageToolbox/MessageToolboxWrapper.d.ts.map +1 -1
  101. package/lib/typescript/src/screens/chat-detail/messageToolbox/useClonePreview.d.ts +18 -0
  102. package/lib/typescript/src/screens/chat-detail/messageToolbox/useClonePreview.d.ts.map +1 -0
  103. package/lib/typescript/src/store/expandedMessage.d.ts +15 -0
  104. package/lib/typescript/src/store/expandedMessage.d.ts.map +1 -0
  105. package/lib/typescript/src/store/index.d.ts +1 -0
  106. package/lib/typescript/src/store/index.d.ts.map +1 -1
  107. package/lib/typescript/src/store/inputState.d.ts +18 -0
  108. package/lib/typescript/src/store/inputState.d.ts.map +1 -0
  109. package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
  110. package/lib/typescript/src/utils/expandableText.d.ts +18 -0
  111. package/lib/typescript/src/utils/expandableText.d.ts.map +1 -0
  112. package/lib/typescript/src/utils/inlineTruncation.d.ts +24 -0
  113. package/lib/typescript/src/utils/inlineTruncation.d.ts.map +1 -0
  114. package/lib/typescript/src/utils/inputState.d.ts +54 -0
  115. package/lib/typescript/src/utils/inputState.d.ts.map +1 -0
  116. package/lib/typescript/src/utils/message.d.ts +8 -0
  117. package/lib/typescript/src/utils/message.d.ts.map +1 -1
  118. package/lib/typescript/src/utils/truncateTextChildren.d.ts +3 -0
  119. package/lib/typescript/src/utils/truncateTextChildren.d.ts.map +1 -0
  120. package/package.json +1 -1
  121. package/src/components/TypingDots/TypingDots.tsx +172 -0
  122. package/src/components/TypingDots/index.ts +2 -0
  123. package/src/components/messages/ExpandableMessageText.tsx +145 -0
  124. package/src/components/messages/PreviewScrollableText.tsx +98 -0
  125. package/src/components/messages/linkMessage/index.tsx +30 -21
  126. package/src/components/messages/quotedMessage/index.tsx +14 -2
  127. package/src/components/messages/textMessage/index.tsx +11 -2
  128. package/src/components/messages/types.ts +18 -0
  129. package/src/core/useChatListener.ts +35 -1
  130. package/src/hooks/groups/useGroupMemberName.ts +31 -0
  131. package/src/hooks/query-keys.ts +2 -0
  132. package/src/hooks/useExpandableText.ts +139 -0
  133. package/src/hooks/useInputState.ts +57 -0
  134. package/src/hooks/useInputStateBroadcast.ts +53 -0
  135. package/src/screens/chat-detail/ChatComposer.tsx +17 -2
  136. package/src/screens/chat-detail/ChatDetail.tsx +11 -0
  137. package/src/screens/chat-detail/ChatListLegend.tsx +2 -0
  138. package/src/screens/chat-detail/ChatTypingIndicator.tsx +89 -0
  139. package/src/screens/chat-detail/PinnedMessagesSheet.tsx +8 -0
  140. package/src/screens/chat-detail/legend/LegendChatMessage.tsx +22 -2
  141. package/src/screens/chat-detail/messageToolbox/MessageToolboxOverlay.tsx +20 -1
  142. package/src/screens/chat-detail/messageToolbox/MessageToolboxWrapper.tsx +111 -5
  143. package/src/screens/chat-detail/messageToolbox/useClonePreview.ts +34 -0
  144. package/src/store/expandedMessage.ts +42 -0
  145. package/src/store/index.ts +1 -0
  146. package/src/store/inputState.ts +76 -0
  147. package/src/translation/resources/i18n.ts +2 -0
  148. package/src/utils/expandableText.ts +51 -0
  149. package/src/utils/inlineTruncation.ts +65 -0
  150. package/src/utils/inputState.ts +104 -0
  151. package/src/utils/message.ts +15 -0
  152. package/src/utils/truncateTextChildren.ts +46 -0
@@ -0,0 +1 @@
1
+ {"version":3,"names":["cloneElement","isValidElement","take","node","budget","text","String","length","slice","Array","isArray","kept","used","child","part","count","push","props","children","undefined","truncateTextChildren","limit"],"sourceRoot":"../../../src","sources":["utils/truncateTextChildren.ts"],"mappings":";;AAAA,SAASA,YAAY,EAAEC,cAAc,QAAwB,OAAO;AAIpE;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,IAAI,GAAGA,CAACC,IAAe,EAAEC,MAAc,KAAY;EACvD,IAAIA,MAAM,IAAI,CAAC,IAAID,IAAI,IAAI,IAAI,IAAI,OAAOA,IAAI,KAAK,SAAS,EAAE;IAC5D,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;EAClB;EAEA,IAAI,OAAOA,IAAI,KAAK,QAAQ,IAAI,OAAOA,IAAI,KAAK,QAAQ,EAAE;IACxD,MAAME,IAAI,GAAGC,MAAM,CAACH,IAAI,CAAC;IACzB,OAAOE,IAAI,CAACE,MAAM,IAAIH,MAAM,GACxB,CAACD,IAAI,EAAEE,IAAI,CAACE,MAAM,CAAC,GACnB,CAACF,IAAI,CAACG,KAAK,CAAC,CAAC,EAAEJ,MAAM,CAAC,EAAEA,MAAM,CAAC;EACrC;EAEA,IAAIK,KAAK,CAACC,OAAO,CAACP,IAAI,CAAC,EAAE;IACvB,MAAMQ,IAAiB,GAAG,EAAE;IAC5B,IAAIC,IAAI,GAAG,CAAC;IACZ,KAAK,MAAMC,KAAK,IAAIV,IAAI,EAAE;MACxB,IAAIS,IAAI,IAAIR,MAAM,EAAE;MACpB,MAAM,CAACU,IAAI,EAAEC,KAAK,CAAC,GAAGb,IAAI,CAACW,KAAK,EAAET,MAAM,GAAGQ,IAAI,CAAC;MAChDD,IAAI,CAACK,IAAI,CAACF,IAAI,CAAC;MACfF,IAAI,IAAIG,KAAK;IACf;IACA,OAAO,CAACJ,IAAI,EAAEC,IAAI,CAAC;EACrB;EAEA,iBAAIX,cAAc,CAA2BE,IAAI,CAAC,EAAE;IAClD,IAAIA,IAAI,CAACc,KAAK,CAACC,QAAQ,KAAKC,SAAS,EAAE,OAAO,CAAChB,IAAI,EAAE,CAAC,CAAC;IACvD,MAAM,CAACe,QAAQ,EAAEN,IAAI,CAAC,GAAGV,IAAI,CAACC,IAAI,CAACc,KAAK,CAACC,QAAQ,EAAEd,MAAM,CAAC;IAC1D,OAAO,cAACJ,YAAY,CAACG,IAAI,EAAEgB,SAAS,EAAED,QAAQ,CAAC,EAAEN,IAAI,CAAC;EACxD;EAEA,OAAO,CAACT,IAAI,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,OAAO,MAAMiB,oBAAoB,GAAGA,CAACjB,IAAe,EAAEkB,KAAa,KACjEnB,IAAI,CAACC,IAAI,EAAEkB,KAAK,CAAC,CAAC,CAAC,CAAC","ignoreList":[]}
@@ -0,0 +1,14 @@
1
+ import { type SvgProps } from 'react-native-svg';
2
+ export interface TypingDotsProps extends Omit<SvgProps, 'fill'> {
3
+ /**
4
+ * Dot colour. Overrides the `fill` SvgProps would otherwise carry, because
5
+ * that one lands on the root <Svg> where the dots' own group already shadows
6
+ * it — passing it there does nothing.
7
+ *
8
+ * Only the colour: the source animates `fill: rgba(26, 29, 34, a)` but never
9
+ * changes the RGB, so the alpha half is driven separately as `fillOpacity`.
10
+ */
11
+ fill?: string;
12
+ }
13
+ export declare const TypingDots: import("react").MemoExoticComponent<({ fill, width, height, ...props }: TypingDotsProps) => import("react").JSX.Element>;
14
+ //# sourceMappingURL=TypingDots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TypingDots.d.ts","sourceRoot":"","sources":["../../../../../src/components/TypingDots/TypingDots.tsx"],"names":[],"mappings":"AAYA,OAAY,EAAW,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAwD/D,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC7D;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAkED,eAAO,MAAM,UAAU,0EAMlB,eAAe,iCAmBnB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { TypingDots } from './TypingDots';
2
+ export type { TypingDotsProps } from './TypingDots';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/TypingDots/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { ComponentProps, ReactNode } from 'react';
2
+ import { KLabel } from '@droppii/libs';
3
+ import type { MessageSurface } from '../../store/expandedMessage';
4
+ type TypoType = ComponentProps<typeof KLabel.Text>['typo'];
5
+ interface ExpandableMessageTextProps {
6
+ messageId: string;
7
+ surface: MessageSurface;
8
+ /** Raw body text — drives the length/newline pre-check only. */
9
+ text: string;
10
+ /**
11
+ * The already-rendered body. Taken as children rather than re-derived from
12
+ * `text` because the three call sites build structurally different bodies
13
+ * (plain run, mention segments, linkified runs) and re-tokenising them here
14
+ * would duplicate three parsers.
15
+ */
16
+ children: ReactNode;
17
+ typo?: TypoType;
18
+ color?: string;
19
+ }
20
+ export declare const ExpandableMessageText: {
21
+ ({ messageId, surface, text, children, typo, color, }: ExpandableMessageTextProps): import("react").JSX.Element;
22
+ displayName: string;
23
+ };
24
+ export {};
25
+ //# sourceMappingURL=ExpandableMessageText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpandableMessageText.d.ts","sourceRoot":"","sources":["../../../../../src/components/messages/ExpandableMessageText.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvD,OAAO,EAAuB,MAAM,EAAE,MAAM,eAAe,CAAC;AAQ5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,KAAK,QAAQ,GAAG,cAAc,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;AAe3D,UAAU,0BAA0B;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,cAAc,CAAC;IACxB,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,qBAAqB;2DAO/B,0BAA0B;;CA0E5B,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { type ReactNode } from 'react';
2
+ /**
3
+ * Set by the toolbox overlay around its clone. `maxHeight` is the space the
4
+ * clone may take; `contentHeight` is how tall the clone currently is.
5
+ * `onScrollableChange` reports whether the text is capped (and so scrolls),
6
+ * because the overlay's tap-to-dismiss would otherwise block that scroll.
7
+ */
8
+ export interface ClonePreviewBudget {
9
+ maxHeight: number;
10
+ contentHeight: number;
11
+ onScrollableChange: (scrollable: boolean) => void;
12
+ }
13
+ export declare const ClonePreviewBudgetContext: import("react").Context<ClonePreviewBudget>;
14
+ /**
15
+ * An expanded message can be taller than the overlay. Scrolling the whole
16
+ * clone clips the bubble along a straight edge — square corners — so inside
17
+ * the overlay the text region scrolls instead and the bubble keeps its shape.
18
+ *
19
+ * Budget: whatever the rest of the clone (padding, quote strip, link card,
20
+ * time row) does not use. `contentHeight` and this box's height arrive from
21
+ * native at different moments, and mixing a fresh one with a stale one makes
22
+ * the cap swing between two sizes indefinitely. So the rest is read only from
23
+ * a consistent pair — while uncapped, when the box equals the natural height —
24
+ * and frozen once a cap is applied, which breaks the feedback loop.
25
+ */
26
+ export declare const PreviewScrollableText: ({ children, }: {
27
+ children: ReactNode;
28
+ }) => import("react").JSX.Element;
29
+ //# sourceMappingURL=PreviewScrollableText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PreviewScrollableText.d.ts","sourceRoot":"","sources":["../../../../../src/components/messages/PreviewScrollableText.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;CACnD;AAED,eAAO,MAAM,yBAAyB,6CACU,CAAC;AAKjD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,GAAI,eAEnC;IACD,QAAQ,EAAE,SAAS,CAAC;CACrB,gCAqDA,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { type BaseLegendMessageProps } from '../types';
2
- export declare const LinkMessage: import("react").MemoExoticComponent<({ message, isOutgoing, createdAtTime, onPressUrl, isHighlighted, isTimeRevealed, groupPosition, }: BaseLegendMessageProps & {
2
+ export declare const LinkMessage: import("react").MemoExoticComponent<({ message, messageId, surface, isOutgoing, createdAtTime, onPressUrl, isHighlighted, isTimeRevealed, groupPosition, }: BaseLegendMessageProps & {
3
3
  onPressUrl?: (url: string) => void;
4
4
  }) => import("react").JSX.Element>;
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/components/messages/linkMessage/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAqB,KAAK,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAmC1E,eAAO,MAAM,WAAW,0IASnB,sBAAsB,GAAG;IAAE,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,iCAgDnE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/components/messages/linkMessage/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAqB,KAAK,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAmC1E,eAAO,MAAM,WAAW,8JAWnB,sBAAsB,GAAG;IAAE,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,iCAuDnE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/components/messages/quotedMessage/index.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAqB,KAAK,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAwB1E,UAAU,kBAAmB,SAAQ,sBAAsB;IACzD,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAED,QAAA,MAAM,aAAa,8CAAgB,kBAAkB,iCAkJnD,CAAC;AAIH,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/components/messages/quotedMessage/index.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAqB,KAAK,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAyB1E,UAAU,kBAAmB,SAAQ,sBAAsB;IACzD,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAED,QAAA,MAAM,aAAa,8CAAgB,kBAAkB,iCA6JnD,CAAC;AAIH,eAAe,aAAa,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { type BaseLegendMessageProps } from '../types';
2
- export declare const TextMessage: import("react").MemoExoticComponent<({ message, isOutgoing, createdAtTime, isHighlighted, isTimeRevealed, onPressUrl, groupPosition, }: BaseLegendMessageProps & {
2
+ export declare const TextMessage: import("react").MemoExoticComponent<({ message, messageId, surface, isOutgoing, createdAtTime, isHighlighted, isTimeRevealed, onPressUrl, groupPosition, }: BaseLegendMessageProps & {
3
3
  onPressUrl?: (url: string) => void;
4
4
  }) => import("react").JSX.Element>;
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/components/messages/textMessage/index.tsx"],"names":[],"mappings":"AASA,OAAO,EAAqB,KAAK,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAkB1E,eAAO,MAAM,WAAW,0IASnB,sBAAsB,GAAG;IAAE,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,iCA6HnE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/components/messages/textMessage/index.tsx"],"names":[],"mappings":"AASA,OAAO,EAAqB,KAAK,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAmB1E,eAAO,MAAM,WAAW,8JAWnB,sBAAsB,GAAG;IAAE,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,iCAmInE,CAAC"}
@@ -1,8 +1,26 @@
1
1
  import type { MediaItem } from '../../hooks/useMediaViewer';
2
2
  import type { MessageItem } from '@droppii/openim-rn-client-sdk';
3
3
  import type { GroupPosition } from '../../utils/legendListMessage';
4
+ import type { MessageSurface } from '../../store/expandedMessage';
4
5
  export interface BaseLegendMessageProps {
5
6
  message: MessageItem;
7
+ /**
8
+ * Resolved once by the caller and threaded down — never re-derived here.
9
+ * The timeline, the pin sheet and the toolbox overlay each compute a
10
+ * message's id differently, and a mismatch silently splits its expansion
11
+ * state across surfaces.
12
+ */
13
+ messageId: string;
14
+ /** Expansion is scoped per surface (BR-003): the same message collapsed in
15
+ * Pin Management while expanded in the timeline, and vice versa. */
16
+ surface: MessageSurface;
17
+ /**
18
+ * Rendered as the toolbox overlay's clone. The clone is touchable so that
19
+ * `Xem thêm` works there (D1), which makes every other press target in the
20
+ * bubble live too — components with a self-contained handler must disable
21
+ * it when this is set.
22
+ */
23
+ isPreview?: boolean;
6
24
  isOutgoing: boolean;
7
25
  createdAtTime: number;
8
26
  isHighlighted?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/components/messages/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAEnE,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,WAAW,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wEAAwE;IACxE,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7D;AAED,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,WAWlD,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/components/messages/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,WAAW,CAAC;IACrB;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;wEACoE;IACpE,OAAO,EAAE,cAAc,CAAC;IACxB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wEAAwE;IACxE,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7D;AAED,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,WAWlD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useChatListener.d.ts","sourceRoot":"","sources":["../../../../src/core/useChatListener.ts"],"names":[],"mappings":"AAkCA,eAAO,MAAM,eAAe,YAob3B,CAAC"}
1
+ {"version":3,"file":"useChatListener.d.ts","sourceRoot":"","sources":["../../../../src/core/useChatListener.ts"],"names":[],"mappings":"AAuCA,eAAO,MAAM,eAAe,YAid3B,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Display name of one group member.
3
+ *
4
+ * Fetches a single member rather than the whole roster: the only place this is
5
+ * needed is the typing sentence, which names at most one person — beyond that
6
+ * the copy collapses to "Nhiều người". Cached by react-query so a dot flickering
7
+ * on and off does not re-hit the SDK.
8
+ */
9
+ export declare const useGroupMemberName: (groupID?: string, userID?: string) => string | undefined;
10
+ //# sourceMappingURL=useGroupMemberName.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGroupMemberName.d.ts","sourceRoot":"","sources":["../../../../../src/hooks/groups/useGroupMemberName.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAC7B,UAAU,MAAM,EAChB,SAAS,MAAM,KACd,MAAM,GAAG,SAeX,CAAC"}
@@ -55,5 +55,6 @@ export declare const groupQueryKeys: {
55
55
  join: () => readonly ["groups", "join"];
56
56
  leave: () => readonly ["groups", "leave"];
57
57
  inviteInfo: (code: string) => readonly ["groups", "inviteInfo", string];
58
+ member: (groupID?: string, userID?: string) => readonly ["groups", "member", string, string];
58
59
  };
59
60
  //# sourceMappingURL=query-keys.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-keys.d.ts","sourceRoot":"","sources":["../../../../src/hooks/query-keys.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe;;uBAEP,MAAM;CAC1B,CAAC;AAEF,eAAO,MAAM,qBAAqB;;;4BAGR,MAAM;;6BAGL,MAAM;0BAET,MAAM;yCACS,MAAM;2BAEpB,MAAM;mCACE,MAAM;gCAIT,MAAM;8BAIR,MAAM;mCACD,MAAM;2BAId,MAAM;iCACA,MAAM;4BACX,MAAM;sBACZ,MAAM;yBACH,MAAM;CAC5B,CAAC;AAEF,eAAO,MAAM,cAAc;;oBAET,MAAM,EAAE;CACzB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,OAAO,qBAAqB,CAAC;AAEjE,eAAO,MAAM,gBAAgB;;;6BAGF,MAAM;;CAGhC,CAAC;AAEF,eAAO,MAAM,uBAAuB;;qBAEjB,MAAM,eAAe,MAAM;CAE7C,CAAC;AAEF,eAAO,MAAM,gBAAgB;;oBAEX,MAAM,mBAAmB,MAAM;CAEhD,CAAC;AAEF,eAAO,MAAM,gBAAgB;;sBAET,MAAM,WAAW,MAAM;CAE1C,CAAC;AAEF,eAAO,MAAM,gBAAgB;;oBAEX,MAAM,SAAS,MAAM;CAEtC,CAAC;AAEF,eAAO,MAAM,cAAc;;;4BAGD,MAAM;;;uBAIX,MAAM;CAE1B,CAAC"}
1
+ {"version":3,"file":"query-keys.d.ts","sourceRoot":"","sources":["../../../../src/hooks/query-keys.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe;;uBAEP,MAAM;CAC1B,CAAC;AAEF,eAAO,MAAM,qBAAqB;;;4BAGR,MAAM;;6BAGL,MAAM;0BAET,MAAM;yCACS,MAAM;2BAEpB,MAAM;mCACE,MAAM;gCAIT,MAAM;8BAIR,MAAM;mCACD,MAAM;2BAId,MAAM;iCACA,MAAM;4BACX,MAAM;sBACZ,MAAM;yBACH,MAAM;CAC5B,CAAC;AAEF,eAAO,MAAM,cAAc;;oBAET,MAAM,EAAE;CACzB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,OAAO,qBAAqB,CAAC;AAEjE,eAAO,MAAM,gBAAgB;;;6BAGF,MAAM;;CAGhC,CAAC;AAEF,eAAO,MAAM,uBAAuB;;qBAEjB,MAAM,eAAe,MAAM;CAE7C,CAAC;AAEF,eAAO,MAAM,gBAAgB;;oBAEX,MAAM,mBAAmB,MAAM;CAEhD,CAAC;AAEF,eAAO,MAAM,gBAAgB;;sBAET,MAAM,WAAW,MAAM;CAE1C,CAAC;AAEF,eAAO,MAAM,gBAAgB;;oBAEX,MAAM,SAAS,MAAM;CAEtC,CAAC;AAEF,eAAO,MAAM,cAAc;;;4BAGD,MAAM;;;uBAIX,MAAM;uBAEN,MAAM,WAAW,MAAM;CAE3C,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { type TextLayoutEvent } from 'react-native';
2
+ import { COLLAPSED_LINES, type MessageSurface } from '../utils/expandableText';
3
+ export { COLLAPSED_LINES };
4
+ export declare const clearExpandableTextCache: () => void;
5
+ export type ExpandableTextMode = 'plain' | 'measuring' | 'fitting' | 'collapsed';
6
+ export declare function useExpandableText(messageId: string, text: string, surface: MessageSurface): {
7
+ mode: ExpandableTextMode;
8
+ cut: number;
9
+ expand: () => void;
10
+ onMeasureTextLayout: ({ nativeEvent: { lines } }: TextLayoutEvent) => void;
11
+ onFitTextLayout: ({ nativeEvent: { lines } }: TextLayoutEvent) => void;
12
+ };
13
+ //# sourceMappingURL=useExpandableText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useExpandableText.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useExpandableText.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAEzE,OAAO,EACL,eAAe,EAGf,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,eAAe,EAAE,CAAC;AAiB3B,eAAO,MAAM,wBAAwB,YAA6B,CAAC;AAsBnE,MAAM,MAAM,kBAAkB,GAC1B,OAAO,GACP,WAAW,GACX,SAAS,GACT,WAAW,CAAC;AAEhB,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,cAAc;;;;sDAwCQ,eAAe;kDAgBf,eAAe;EAuB/C"}
@@ -0,0 +1,21 @@
1
+ import { type InputStateRecord } from '../utils/inputState';
2
+ export interface InputStateResult {
3
+ /**
4
+ * Whether the indicator belongs on screen. Unlike the sentence this needs no
5
+ * name, so it can be answered here.
6
+ */
7
+ isTyping: boolean;
8
+ /** Everyone still inside the window, oldest signal first. */
9
+ typers: readonly InputStateRecord[];
10
+ }
11
+ /**
12
+ * Typing state for one conversation.
13
+ *
14
+ * Expiry is read from each record's timestamp rather than tracked with a timer
15
+ * per user, and the hook schedules a single wake-up at the moment the next
16
+ * typer falls out of the window. So with A typing at t=0 and B at t=2s the
17
+ * sentence moves from A, to both, to B alone at t=3s, and disappears at t=5s —
18
+ * without polling between those points.
19
+ */
20
+ export declare const useInputState: (conversationID?: string) => InputStateResult;
21
+ //# sourceMappingURL=useInputState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInputState.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useInputState.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,6DAA6D;IAC7D,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACrC;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,GAAI,iBAAiB,MAAM,KAAG,gBA6BvD,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Broadcasts this device's composing state for a conversation.
3
+ *
4
+ * The SDK throttles the outgoing frames itself, so `notifyTyping` is safe to
5
+ * call on every keystroke — no debounce here would only duplicate that. What
6
+ * this hook does own is the start/stop rule: an empty draft counts as stopping,
7
+ * not as typing, and leaving the screen has to stop too or the peer is left
8
+ * watching an indicator for a composer nobody is in front of.
9
+ */
10
+ export declare const useInputStateBroadcast: (conversationID?: string) => {
11
+ notifyTyping: (text?: string) => void;
12
+ notifyStoppedTyping: () => void;
13
+ };
14
+ //# sourceMappingURL=useInputStateBroadcast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInputStateBroadcast.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useInputStateBroadcast.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,GAAI,iBAAiB,MAAM;0BAyBlD,MAAM;;CAejB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ChatComposer.d.ts","sourceRoot":"","sources":["../../../../../src/screens/chat-detail/ChatComposer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,IAAI,EACV,MAAM,cAAc,CAAC;AA8BtB,OAAO,EAA6B,KAAK,iBAAiB,EAAE,MAAM,SAAS,CAAC;AA+B5E,UAAU,yBAAyB;IACjC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACpC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,WAAW,CAAC,EAAE,SAAS,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IACrC,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACtD,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,eAAO,MAAM,YAAY,+JASpB,yBAAyB,iCA+nB7B,CAAC"}
1
+ {"version":3,"file":"ChatComposer.d.ts","sourceRoot":"","sources":["../../../../../src/screens/chat-detail/ChatComposer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,IAAI,EACV,MAAM,cAAc,CAAC;AA8BtB,OAAO,EAA6B,KAAK,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAgC5E,UAAU,yBAAyB;IACjC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACpC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,WAAW,CAAC,EAAE,SAAS,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IACrC,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACtD,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,eAAO,MAAM,YAAY,+JASpB,yBAAyB,iCA6oB7B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ChatDetail.d.ts","sourceRoot":"","sources":["../../../../../src/screens/chat-detail/ChatDetail.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAkV/C,QAAA,MAAM,YAAY,GAAI,OAAO,eAAe,gCAS3C,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"ChatDetail.d.ts","sourceRoot":"","sources":["../../../../../src/screens/chat-detail/ChatDetail.tsx"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AA2V/C,QAAA,MAAM,YAAY,GAAI,OAAO,eAAe,gCAS3C,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ChatListLegend.d.ts","sourceRoot":"","sources":["../../../../../src/screens/chat-detail/ChatListLegend.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAQf,OAAiB,EAKf,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AAMjC,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,8BAA8B,CAAC;AActC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAmF7C,UAAU,2BAA4B,SAAQ,aAAa;IACzD,OAAO,EAAE,SAAS,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IACzC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,kBAAkB,EAAE,CAAC,IAAI,EAAE;QACzB,QAAQ,EAAE,OAAO,CAAC;QAClB,aAAa,EAAE,OAAO,CAAC;KACxB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,cAAc,2SAmBtB,2BAA2B,iCAo2B/B,CAAC"}
1
+ {"version":3,"file":"ChatListLegend.d.ts","sourceRoot":"","sources":["../../../../../src/screens/chat-detail/ChatListLegend.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAQf,OAAiB,EAKf,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AAMjC,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,8BAA8B,CAAC;AActC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAoF7C,UAAU,2BAA4B,SAAQ,aAAa;IACzD,OAAO,EAAE,SAAS,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IACzC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,kBAAkB,EAAE,CAAC,IAAI,EAAE;QACzB,QAAQ,EAAE,OAAO,CAAC;QAClB,aAAa,EAAE,OAAO,CAAC;KACxB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,cAAc,2SAmBtB,2BAA2B,iCAq2B/B,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * "<name> đang nhập..." above the composer, with the bouncing dots.
3
+ *
4
+ * Renders nothing while nobody is typing — an empty row would reserve height
5
+ * and nudge the message list every time somebody started or stopped.
6
+ */
7
+ export declare const ChatTypingIndicator: import("react").MemoExoticComponent<() => import("react").JSX.Element>;
8
+ //# sourceMappingURL=ChatTypingIndicator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatTypingIndicator.d.ts","sourceRoot":"","sources":["../../../../../src/screens/chat-detail/ChatTypingIndicator.tsx"],"names":[],"mappings":"AAWA;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,wEAsD9B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"PinnedMessagesSheet.d.ts","sourceRoot":"","sources":["../../../../../src/screens/chat-detail/PinnedMessagesSheet.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAwL9E,MAAM,WAAW,6BAA6B;IAC5C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,wBAAwB,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,SAAS,CAAC;IAC5D,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;CACjD;AAED,eAAO,MAAM,uBAAuB,GAAI,4EAKrC,6BAA6B,SAmB/B,CAAC"}
1
+ {"version":3,"file":"PinnedMessagesSheet.d.ts","sourceRoot":"","sources":["../../../../../src/screens/chat-detail/PinnedMessagesSheet.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,+BAA+B,CAAC;AA0L9E,MAAM,WAAW,6BAA6B;IAC5C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,wBAAwB,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,SAAS,CAAC;IAC5D,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;CACjD;AAED,eAAO,MAAM,uBAAuB,GAAI,4EAKrC,6BAA6B,SAyB/B,CAAC"}
@@ -2,6 +2,7 @@ import type { ReactNode } from 'react';
2
2
  import type { MessageItem } from '@droppii/openim-rn-client-sdk';
3
3
  import type { MediaItem } from '../../../hooks/useMediaViewer';
4
4
  import type { GroupPosition } from '../../../utils/legendListMessage';
5
+ import type { MessageSurface } from '../../../store/expandedMessage';
5
6
  interface LegendChatMessageProps {
6
7
  message: MessageItem;
7
8
  /** Stable per-row id (see getMessageRenderId) — bound into onPress/onLongPress locally so those callbacks stay referentially stable across unrelated list re-renders. */
@@ -38,7 +39,16 @@ interface LegendChatMessageProps {
38
39
  showSenderGutter?: boolean;
39
40
  /** Position within its same-sender cluster — drives the bubble tail. */
40
41
  groupPosition?: GroupPosition;
42
+ /**
43
+ * Which surface is rendering this message. Expansion state is scoped by it
44
+ * (BR-003), so Pin Management must pass `'pin'` explicitly — the default
45
+ * keeps the timeline and the toolbox overlay sharing one scope, which is
46
+ * what makes the overlay clone mirror the row it lifted from.
47
+ */
48
+ surface?: MessageSurface;
49
+ /** Toolbox overlay clone — see `BaseLegendMessageProps.isPreview`. */
50
+ isPreview?: boolean;
41
51
  }
42
- export declare const LegendChatMessage: import("react").MemoExoticComponent<({ message, messageId, isOutgoing, createdAtTime, onMediaPress, onPressUrl, onRetry, onPress, alwaysHandlePress, onLongPress, customMessageItemFactory, isHighlighted, isTimeRevealed, showName, showAvatar, showSenderGutter, groupPosition, }: LegendChatMessageProps) => string | number | bigint | true | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode>> | import("react").JSX.Element>;
52
+ export declare const LegendChatMessage: import("react").MemoExoticComponent<({ message, messageId, isOutgoing, createdAtTime, onMediaPress, onPressUrl, onRetry, onPress, alwaysHandlePress, onLongPress, customMessageItemFactory, isHighlighted, isTimeRevealed, showName, showAvatar, showSenderGutter, groupPosition, surface, isPreview, }: LegendChatMessageProps) => string | number | bigint | true | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode>> | import("react").JSX.Element>;
43
53
  export {};
44
54
  //# sourceMappingURL=LegendChatMessage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LegendChatMessage.d.ts","sourceRoot":"","sources":["../../../../../../src/screens/chat-detail/legend/LegendChatMessage.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAoC,SAAS,EAAE,MAAM,OAAO,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAGjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAe/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAStE,UAAU,sBAAsB;IAC9B,OAAO,EAAE,WAAW,CAAC;IACrB,yKAAyK;IACzK,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5D,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IACzC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IAChE,wBAAwB,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,SAAS,CAAC;IACzD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,wEAAwE;IACxE,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAsCD,eAAO,MAAM,iBAAiB,uRAmBzB,sBAAsB,wRA8G1B,CAAC"}
1
+ {"version":3,"file":"LegendChatMessage.d.ts","sourceRoot":"","sources":["../../../../../../src/screens/chat-detail/legend/LegendChatMessage.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAoC,SAAS,EAAE,MAAM,OAAO,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAGjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAe/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AASrE,UAAU,sBAAsB;IAC9B,OAAO,EAAE,WAAW,CAAC;IACrB,yKAAyK;IACzK,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5D,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IACzC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IAChE,wBAAwB,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,SAAS,CAAC;IACzD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,wEAAwE;IACxE,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,sEAAsE;IACtE,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAsCD,eAAO,MAAM,iBAAiB,2SAqBzB,sBAAsB,wRAsH1B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"MessageToolboxOverlay.d.ts","sourceRoot":"","sources":["../../../../../../src/screens/chat-detail/messageToolbox/MessageToolboxOverlay.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAEV,iBAAiB,EAElB,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAG3D,OAAO,EAEL,KAAK,WAAW,EACjB,MAAM,+BAA+B,CAAC;AAcvC,UAAU,0BAA0B;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wBAAwB,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,SAAS,CAAC;IAC5D,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IAC9C,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IAIhD,MAAM,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;CAC/B;AAED,eAAO,MAAM,qBAAqB,0HAsNjC,CAAC"}
1
+ {"version":3,"file":"MessageToolboxOverlay.d.ts","sourceRoot":"","sources":["../../../../../../src/screens/chat-detail/messageToolbox/MessageToolboxOverlay.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAEV,iBAAiB,EAElB,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAG3D,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,+BAA+B,CAAC;AAqBvC,UAAU,0BAA0B;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wBAAwB,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,SAAS,CAAC;IAC5D,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IAC9C,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IAIhD,MAAM,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;CAC/B;AAED,eAAO,MAAM,qBAAqB,0HAiOjC,CAAC"}
@@ -3,9 +3,22 @@ type MessageToolboxWrapperProps = {
3
3
  isOutgoing?: boolean;
4
4
  rect: MeasuredRect;
5
5
  message?: React.ReactNode;
6
+ /**
7
+ * Lets touches reach the clone's own press targets — needed for `Xem thêm`
8
+ * (D1). Off by default: types like FileMessage and consumer custom nodes
9
+ * have self-contained handlers that must stay inert here.
10
+ */
11
+ isCloneInteractive?: boolean;
12
+ /**
13
+ * Tapping the bubble used to fall through to the backdrop and dismiss. The
14
+ * ScrollView below is hit-testable and swallows that, so the gesture is
15
+ * reinstated explicitly. A touch that a press target inside the clone
16
+ * claims (`Xem thêm`) never reaches it.
17
+ */
18
+ onDismiss?: () => void;
6
19
  reaction?: React.ReactNode;
7
20
  toolbox?: React.ReactNode;
8
21
  };
9
- export declare const MessageToolboxWrapper: import("react").MemoExoticComponent<({ isOutgoing, rect, message, reaction, toolbox, }: MessageToolboxWrapperProps) => import("react").JSX.Element>;
22
+ export declare const MessageToolboxWrapper: import("react").MemoExoticComponent<({ isOutgoing, rect, message, isCloneInteractive, onDismiss, reaction, toolbox, }: MessageToolboxWrapperProps) => import("react").JSX.Element>;
10
23
  export {};
11
24
  //# sourceMappingURL=MessageToolboxWrapper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageToolboxWrapper.d.ts","sourceRoot":"","sources":["../../../../../../src/screens/chat-detail/messageToolbox/MessageToolboxWrapper.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAO5C,KAAK,0BAA0B,GAAG;IAChC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,qBAAqB,0FAO7B,0BAA0B,iCAgF9B,CAAC"}
1
+ {"version":3,"file":"MessageToolboxWrapper.d.ts","sourceRoot":"","sources":["../../../../../../src/screens/chat-detail/messageToolbox/MessageToolboxWrapper.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAY5C,KAAK,0BAA0B,GAAG;IAChC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,qBAAqB,yHAS7B,0BAA0B,iCAuI9B,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { ClonePreviewBudget } from '../../../components/messages/PreviewScrollableText';
2
+ /**
3
+ * Wiring between the overlay's clone and the expanded text that scrolls
4
+ * inside it (see `PreviewScrollableText`).
5
+ *
6
+ * `dismissDisabled`: the clone sits in a tap-to-dismiss Pressable. On iOS a
7
+ * ScrollView refuses to scroll while an ANCESTOR holds the JS responder
8
+ * (`RCTScrollView _shouldDisableScrollInteraction`), so with the Pressable
9
+ * enabled a drag on the text never scrolls — it ends as a tap and closes the
10
+ * overlay. While the text is scrollable the Pressable stands down; the
11
+ * backdrop and the menu still dismiss.
12
+ */
13
+ export declare const useClonePreview: (maxHeight: number) => {
14
+ budget: ClonePreviewBudget;
15
+ onContentSizeChange: (_width: number, height: number) => void;
16
+ dismissDisabled: boolean;
17
+ };
18
+ //# sourceMappingURL=useClonePreview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useClonePreview.d.ts","sourceRoot":"","sources":["../../../../../../src/screens/chat-detail/messageToolbox/useClonePreview.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oDAAoD,CAAC;AAE7F;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAAI,WAAW,MAAM;;kCAKpC,MAAM,UAAU,MAAM;;CAclC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { expandedKey, type MessageSurface } from '../utils/expandableText';
2
+ export type { MessageSurface };
3
+ export { expandedKey };
4
+ export interface ExpandedMessageStore {
5
+ /**
6
+ * Flat record rather than a Set so a row can subscribe with a cheap boolean
7
+ * selector — `useExpandedMessageStore(s => !!s.expanded[key])` — which stays
8
+ * referentially stable for every message the change didn't touch.
9
+ */
10
+ expanded: Record<string, true>;
11
+ expand: (surface: MessageSurface, messageId: string) => void;
12
+ clearSurface: (surface: MessageSurface) => void;
13
+ }
14
+ export declare const useExpandedMessageStore: import("zustand").UseBoundStore<import("zustand").StoreApi<ExpandedMessageStore>>;
15
+ //# sourceMappingURL=expandedMessage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expandedMessage.d.ts","sourceRoot":"","sources":["../../../../src/store/expandedMessage.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EAEX,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EAAE,cAAc,EAAE,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,CAAC;AAEvB,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC/B,MAAM,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,YAAY,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;CACjD;AAED,eAAO,MAAM,uBAAuB,mFAoBnC,CAAC"}
@@ -1,4 +1,5 @@
1
1
  export * from './storeConfig';
2
2
  export * from './user';
3
3
  export * from './conversation';
4
+ export * from './inputState';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/store/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/store/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { ConversationInputStatus } from '@droppii/openim-rn-client-sdk';
2
+ import type { InputStateMap } from '../utils/inputState';
3
+ export interface InputStateStore {
4
+ /** conversationID -> userID -> record. */
5
+ byConversation: InputStateMap;
6
+ /**
7
+ * Apply one OnInputStatusChanged payload.
8
+ *
9
+ * A non-empty `platformIDs` means that user is composing; an empty list is
10
+ * how the SDK reports that they stopped, so it removes them outright rather
11
+ * than storing an inactive record.
12
+ */
13
+ applyInputStatus: (status: ConversationInputStatus) => void;
14
+ /** Remove one user now — their message arrived, or they went idle. */
15
+ removeTyper: (conversationID: string, userID: string) => void;
16
+ }
17
+ export declare const useInputStateStore: import("zustand").UseBoundStore<import("zustand").StoreApi<InputStateStore>>;
18
+ //# sourceMappingURL=inputState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputState.d.ts","sourceRoot":"","sources":["../../../../src/store/inputState.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,KAAK,EAEV,aAAa,EACd,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,cAAc,EAAE,aAAa,CAAC;IAC9B;;;;;;OAMG;IACH,gBAAgB,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAC5D,sEAAsE;IACtE,WAAW,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/D;AAaD,eAAO,MAAM,kBAAkB,8EA0C5B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../../../src/translation/resources/i18n.ts"],"names":[],"mappings":";;;AA6OA,wBAEE"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../../../src/translation/resources/i18n.ts"],"names":[],"mappings":";;;AA+OA,wBAEE"}
@@ -0,0 +1,18 @@
1
+ export type MessageSurface = 'timeline' | 'pin';
2
+ export declare const COLLAPSED_LINES = 5;
3
+ export declare const expandedKey: (surface: MessageSurface, messageId: string) => string;
4
+ /**
5
+ * Character count alone is not an approximation of rendered lines — it is
6
+ * wrong for the shapes this chat carries most (pasted addresses, order lists),
7
+ * where an eight-line message can be under 70 characters. Newlines cost one
8
+ * character and a whole line, so both signals are needed. Message text is
9
+ * sender-controlled, so a length-only gate is also trivially defeated.
10
+ */
11
+ export declare const isMeasurementCandidate: (text: string) => boolean;
12
+ /**
13
+ * Returns a copy without the entries belonging to `surface`, or the original
14
+ * reference when nothing matched — callers use that identity to skip a
15
+ * pointless store update.
16
+ */
17
+ export declare const withoutSurface: (expanded: Record<string, true>, surface: MessageSurface) => Record<string, true>;
18
+ //# sourceMappingURL=expandableText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expandableText.d.ts","sourceRoot":"","sources":["../../../../src/utils/expandableText.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,KAAK,CAAC;AAEhD,eAAO,MAAM,eAAe,IAAI,CAAC;AAIjC,eAAO,MAAM,WAAW,GAAI,SAAS,cAAc,EAAE,WAAW,MAAM,WAC3C,CAAC;AAU5B;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,GAAI,MAAM,MAAM,YAEX,CAAC;AAEzC;;;;GAIG;AACH,eAAO,MAAM,cAAc,GACzB,UAAU,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,EAC9B,SAAS,cAAc,KACtB,MAAM,CAAC,MAAM,EAAE,IAAI,CAcrB,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Cut-point arithmetic for the inline `... Xem thêm` preview. Everything here
3
+ * works on the lines RN reports from `onTextLayout`, whose `text` includes the
4
+ * line's trailing break — so joining them reproduces the rendered string and a
5
+ * running length is a valid character offset into it.
6
+ */
7
+ export interface RenderedLine {
8
+ text: string;
9
+ }
10
+ export declare const joinLines: (lines: readonly RenderedLine[]) => string;
11
+ /**
12
+ * Backs `cut` off trailing whitespace — a kept `\n` would push the suffix onto
13
+ * a line of its own — and off half an emoji, which would render as a tofu box.
14
+ */
15
+ export declare const settleCut: (full: string, cut: number) => number;
16
+ /** First guess: everything on the first `maxLines` lines. */
17
+ export declare const initialCut: (lines: readonly RenderedLine[], maxLines: number) => number;
18
+ /**
19
+ * The suffix did not fit and wrapped past `maxLines`. Drop at least as many
20
+ * characters as spilled over — the spill includes the suffix itself, so this
21
+ * converges in one or two passes — then prefer ending on a word.
22
+ */
23
+ export declare const shrinkCut: (full: string, cut: number, fittedLines: readonly RenderedLine[], maxLines: number) => number;
24
+ //# sourceMappingURL=inlineTruncation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inlineTruncation.d.ts","sourceRoot":"","sources":["../../../../src/utils/inlineTruncation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd;AAUD,eAAO,MAAM,SAAS,GAAI,OAAO,SAAS,YAAY,EAAE,WACf,CAAC;AAE1C;;;GAGG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,EAAE,KAAK,MAAM,WAKlD,CAAC;AAEF,6DAA6D;AAC7D,eAAO,MAAM,UAAU,GACrB,OAAO,SAAS,YAAY,EAAE,EAC9B,UAAU,MAAM,WAIjB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,SAAS,GACpB,MAAM,MAAM,EACZ,KAAK,MAAM,EACX,aAAa,SAAS,YAAY,EAAE,EACpC,UAAU,MAAM,WAcjB,CAAC"}
@@ -0,0 +1,54 @@
1
+ import type { Platform } from '@droppii/openim-rn-client-sdk';
2
+ /** A typer drops out this long after their last signal — BR-002. */
3
+ export declare const INPUT_STATE_TTL = 3000;
4
+ export interface InputStateRecord {
5
+ userID: string;
6
+ /** Devices that user is composing from. An empty list means they stopped. */
7
+ platformIDs: Platform[];
8
+ /** When their most recent signal arrived — the clock the TTL runs against. */
9
+ updatedAt: number;
10
+ }
11
+ /** userID -> record, for one conversation. */
12
+ export type ConversationInputState = Readonly<Record<string, InputStateRecord>>;
13
+ /** conversationID -> that conversation's typers. */
14
+ export type InputStateMap = Readonly<Record<string, ConversationInputState>>;
15
+ /**
16
+ * Typers still inside the TTL window, oldest signal first.
17
+ *
18
+ * Expiry is derived from `updatedAt` rather than driven by one timer per user:
19
+ * the whole point is that each typer runs on their own clock. With A typing at
20
+ * t=0 and B at t=2s, A has to drop at t=3s while B stays until t=5s — a single
21
+ * shared timer reset by the newest signal would keep both alive to t=5s.
22
+ */
23
+ export declare const getActiveTypers: (state: ConversationInputState | undefined, now: number) => readonly InputStateRecord[];
24
+ /**
25
+ * When the next active typer falls out of the window, or null if none will.
26
+ *
27
+ * The caller uses this to wake up exactly once per expiry instead of polling.
28
+ */
29
+ export declare const getNextExpiryAt: (state: ConversationInputState | undefined, now: number) => number | null;
30
+ export declare const truncateTypingName: (name: string) => string;
31
+ /**
32
+ * Which copy to render, as a key plus its values.
33
+ *
34
+ * Deliberately not a finished string: the name is styled differently from the
35
+ * rest of the sentence, so the caller needs the pieces separately to hand them
36
+ * to a rich-text renderer. Keeping translation out of here also leaves this
37
+ * module free of any dependency on the i18n layer.
38
+ */
39
+ export interface TypingTextDescriptor {
40
+ key: string;
41
+ values?: Record<string, string>;
42
+ }
43
+ export declare const TYPING_TEXT_KEYS: {
44
+ readonly single: "chat:typing_single";
45
+ readonly multiple: "chat:typing_multiple";
46
+ };
47
+ /**
48
+ * Copy for a set of typers, or null when the indicator should be hidden.
49
+ *
50
+ * Only one typer is ever named. Beyond that the sentence collapses, so the
51
+ * caller never has to resolve a second name.
52
+ */
53
+ export declare const resolveTypingText: (typerCount: number, singleName?: string) => TypingTextDescriptor | null;
54
+ //# sourceMappingURL=inputState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputState.d.ts","sourceRoot":"","sources":["../../../../src/utils/inputState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAE9D,oEAAoE;AACpE,eAAO,MAAM,eAAe,OAAQ,CAAC;AAKrC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,WAAW,EAAE,QAAQ,EAAE,CAAC;IACxB,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,8CAA8C;AAC9C,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAEhF,oDAAoD;AACpD,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC,CAAC;AAI7E;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,sBAAsB,GAAG,SAAS,EACzC,KAAK,MAAM,KACV,SAAS,gBAAgB,EAU3B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,sBAAsB,GAAG,SAAS,EACzC,KAAK,MAAM,KACV,MAAM,GAAG,IAMX,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,MAGxC,CAAC;AAEX;;;;;;;GAOG;AACH,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,eAAO,MAAM,gBAAgB;;;CAGnB,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC5B,YAAY,MAAM,EAClB,aAAa,MAAM,KAClB,oBAAoB,GAAG,IAQzB,CAAC"}