@ethora/chat-component 26.9.6 → 26.9.8

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 (57) hide show
  1. package/README.md +44 -2
  2. package/dist/{ChatProfileModal-DKuxJsdM.js → ChatProfileModal-3UH0H5Ec.js} +571 -567
  3. package/dist/{FilePreviewModal-BcaSoO3-.js → FilePreviewModal-Cgj1iHry.js} +168 -168
  4. package/dist/{ManageDataModal-Dw4dCQll.js → ManageDataModal-BblTuE9g.js} +14 -14
  5. package/dist/{MarkdownBody-xtKDMR0h.js → MarkdownBody-RMEx8yW2.js} +1 -1
  6. package/dist/{MessageSearchModal-BVKU6H3v.js → MessageSearchModal-CrYR2EH8.js} +105 -113
  7. package/dist/{PublicChatsModal-CscOnVaQ.js → PublicChatsModal-Bi5r4mrV.js} +13 -13
  8. package/dist/{SideDrawer-WneDrrWG.js → SideDrawer-CDAoobvX.js} +16 -16
  9. package/dist/{UserProfileModal-CMHFq1I9.js → UserProfileModal-4Frgvam-.js} +3 -3
  10. package/dist/{UserSettingsModal-BoZXZ0oR.js → UserSettingsModal-C-mb-9cb.js} +2 -2
  11. package/dist/{VideoCallOverlay-CQNi7wp5.js → VideoCallOverlay-92dFLb9U.js} +1 -1
  12. package/dist/{VisibilityModal-BPsNiMzJ.js → VisibilityModal-zIAV6dAP.js} +9 -9
  13. package/dist/components/InputComponents/MentionDropdown.d.ts +2 -0
  14. package/dist/components/MainComponents/scrollAnchor.d.ts +19 -0
  15. package/dist/components/MainComponents/useJumpToMessage.d.ts +42 -11
  16. package/dist/components/MainComponents/useScrollAnchor.d.ts +29 -0
  17. package/dist/components/Modals/MessageSearchModal/MessageHitResults.d.ts +5 -0
  18. package/dist/components/Modals/styledModalComponents.d.ts +0 -8
  19. package/dist/{handleCopyClick-B70vLjJD.js → handleCopyClick-BtXos0AJ.js} +1 -1
  20. package/dist/helpers/checkUniqueUsers.d.ts +2 -2
  21. package/dist/helpers/dedupeMembers.d.ts +10 -0
  22. package/dist/helpers/historyPreloadConfig.d.ts +25 -0
  23. package/dist/helpers/historyPreloadScheduler.d.ts +3 -0
  24. package/dist/helpers/insertMessageWithDelimiter.d.ts +1 -0
  25. package/dist/helpers/isMessageSearchEnabled.d.ts +9 -0
  26. package/dist/helpers/jumpThread.d.ts +56 -0
  27. package/dist/helpers/jumpWindow.d.ts +73 -0
  28. package/dist/helpers/openThreadForJump.d.ts +26 -0
  29. package/dist/helpers/pdf/loadPdfjs.d.ts +8 -1
  30. package/dist/helpers/roomUserCount.d.ts +19 -0
  31. package/dist/helpers/userResolver.d.ts +57 -0
  32. package/dist/helpers/xmppIdShape.d.ts +1 -1
  33. package/dist/hooks/useChatWrapperInit.d.ts +6 -0
  34. package/dist/hooks/usePdfThumbnail.d.ts +2 -1
  35. package/dist/hooks/useRoomDirectory.d.ts +11 -0
  36. package/dist/{main-rJpE4hh-.js → main-BnLtessp.js} +22850 -21155
  37. package/dist/main.css +1 -1
  38. package/dist/main.js +11 -11
  39. package/dist/networking/api-requests/roomMembers.api.d.ts +18 -0
  40. package/dist/networking/ethoraEvents.d.ts +44 -0
  41. package/dist/networking/stanzaHandlers.d.ts +2 -2
  42. package/dist/networking/xmpp/allRoomPresences.xmpp.d.ts +18 -1
  43. package/dist/networking/xmpp/presenceInRoom.xmpp.d.ts +1 -1
  44. package/dist/networking/xmppClient.d.ts +56 -2
  45. package/dist/roomStore/Middleware/jumpThreadMiddleware.d.ts +2 -0
  46. package/dist/roomStore/index.d.ts +12 -0
  47. package/dist/roomStore/roomsSlice.d.ts +33 -1
  48. package/dist/roomStore/safeKey.d.ts +12 -0
  49. package/dist/roomStore/usersSetCap.d.ts +15 -0
  50. package/dist/types/models/config.model.d.ts +70 -3
  51. package/dist/types/models/room.model.d.ts +14 -0
  52. package/dist/types/models/xmpp.model.d.ts +21 -1
  53. package/dist/version.d.ts +1 -1
  54. package/package.json +2 -1
  55. package/dist/components/MainComponents/computeAnchoredScrollTop.d.ts +0 -9
  56. package/dist/components/Modals/NewChatModal/UpdNewChatModal.d.ts +0 -3
  57. package/dist/components/SortDropDown/index.d.ts +0 -8
@@ -1,6 +1,6 @@
1
1
  import { jsxs as i, jsx as o } from "react/jsx-runtime";
2
2
  import { useId as f, useRef as v } from "react";
3
- import { p as u, y as g, aI as m, aO as w, B as b, aP as y, x as e, aQ as D, aR as k } from "./main-rJpE4hh-.js";
3
+ import { p as u, y as g, aO as m, aV as w, B as b, aW as y, x as e, aX as D, aY as k } from "./main-BnLtessp.js";
4
4
  const c = 767, R = `${c}px`, z = e.div`
5
5
  position: relative;
6
6
  pointer-events: auto;
@@ -62,7 +62,7 @@ const c = 767, R = `${c}px`, z = e.div`
62
62
  display: flex;
63
63
  flex-direction: column;
64
64
  gap: var(--ethora-space-2, 8px);
65
- `, $ = e.h3`
65
+ `, W = e.h3`
66
66
  margin: 0;
67
67
  padding: 0 var(--ethora-space-1, 4px);
68
68
  font-size: var(--ethora-font-size-xs, 12px);
@@ -70,7 +70,7 @@ const c = 767, R = `${c}px`, z = e.div`
70
70
  letter-spacing: 0.06em;
71
71
  text-transform: uppercase;
72
72
  color: var(--ethora-color-text-muted, #8c8c8c);
73
- `, W = e.div`
73
+ `, $ = e.div`
74
74
  display: flex;
75
75
  flex-direction: column;
76
76
  box-sizing: border-box;
@@ -89,7 +89,7 @@ const c = 767, R = `${c}px`, z = e.div`
89
89
  align-items: baseline;
90
90
  justify-content: space-between;
91
91
  gap: var(--ethora-space-2, 8px);
92
- `, F = e.button`
92
+ `, V = e.button`
93
93
  border: none;
94
94
  background: transparent;
95
95
  padding: var(--ethora-space-2, 8px) 0;
@@ -109,11 +109,11 @@ const c = 767, R = `${c}px`, z = e.div`
109
109
  outline-offset: 2px;
110
110
  border-radius: var(--ethora-radius-sm, 8px);
111
111
  }
112
- `, Q = e.div`
112
+ `, X = e.div`
113
113
  height: 1px;
114
114
  margin: 0 var(--ethora-space-4, 16px);
115
115
  background-color: var(--ethora-color-border, #e6e8ec);
116
- `, V = e.div`
116
+ `, F = e.div`
117
117
  display: flex;
118
118
  align-items: center;
119
119
  gap: var(--ethora-space-2, 8px);
@@ -135,7 +135,7 @@ const c = 767, R = `${c}px`, z = e.div`
135
135
  & > svg {
136
136
  flex: 0 0 auto;
137
137
  }
138
- `, X = e.input`
138
+ `, Y = e.input`
139
139
  flex: 1 1 auto;
140
140
  min-width: 0;
141
141
  border: none;
@@ -192,11 +192,11 @@ const c = 767, R = `${c}px`, z = e.div`
192
192
  gap: var(--ethora-space-1, 4px);
193
193
  flex: 1 1 auto;
194
194
  min-width: 0;
195
- `, P = e.span`
195
+ `, j = e.span`
196
196
  flex: 0 0 auto;
197
197
  display: inline-flex;
198
198
  color: var(--ethora-color-text-muted, #8c8c8c);
199
- `, j = () => /* @__PURE__ */ o("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ o(
199
+ `, M = () => /* @__PURE__ */ o("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ o(
200
200
  "path",
201
201
  {
202
202
  d: "M6 3.5L10.5 8L6 12.5",
@@ -214,7 +214,7 @@ const c = 767, R = `${c}px`, z = e.div`
214
214
  /* @__PURE__ */ o(T, { children: r }),
215
215
  a && /* @__PURE__ */ o(C, { children: a })
216
216
  ] }),
217
- /* @__PURE__ */ o(P, { "aria-hidden": "true", children: /* @__PURE__ */ o(j, {}) })
217
+ /* @__PURE__ */ o(j, { "aria-hidden": "true", children: /* @__PURE__ */ o(M, {}) })
218
218
  ] }), J = ({
219
219
  title: r,
220
220
  onClose: a,
@@ -255,16 +255,16 @@ const c = 767, R = `${c}px`, z = e.div`
255
255
  export {
256
256
  O as D,
257
257
  J as S,
258
- $ as a,
259
- W as b,
260
- Q as c,
258
+ W as a,
259
+ $ as b,
260
+ X as c,
261
261
  G as d,
262
262
  _ as e,
263
263
  C as f,
264
264
  T as g,
265
265
  K as h,
266
- V as i,
267
- X as j,
266
+ F as i,
267
+ Y as j,
268
268
  q as k,
269
- F as l
269
+ V as l
270
270
  };
@@ -1,8 +1,8 @@
1
1
  import { jsxs as u, Fragment as $, jsx as o } from "react/jsx-runtime";
2
2
  import { forwardRef as ge, useState as I, useCallback as y, useImperativeHandle as ve, useRef as ae, useMemo as M } from "react";
3
- import { a as be, p as J, t as ye, v as xe, w as we, P as re, I as H, x as D, y as Ce, z as Se, C as Ie, D as te, E as De, F as Ne, G as ke, J as Ue, u as Q, K as Fe, L as Pe, N as Ae, O as Re, Q as Y, q as Z, R as ze, S as je, T as Be, s as $e, B as X, U as Ee, W as Oe, X as Te, Y as ee, Z as R, _ as Le, $ as Me, V as He, A as Xe, a0 as We, a1 as Je, a2 as Ke, a3 as Ve } from "./main-rJpE4hh-.js";
4
- import { D as E, a as W, b as Ge, e as qe, f as _e, S as Qe } from "./SideDrawer-WneDrrWG.js";
5
- import { P as ne, a as Ye, D as Ze, b as eo, h as oo } from "./handleCopyClick-B70vLjJD.js";
3
+ import { a as be, p as J, t as ye, v as xe, w as we, P as re, I as H, x as D, y as Ce, z as Se, C as Ie, D as te, E as De, F as Ne, G as ke, J as Ue, u as Q, K as Fe, L as Pe, N as Ae, O as Re, Q as Y, q as Z, R as ze, S as je, T as Be, s as $e, B as X, U as Ee, W as Oe, X as Te, Y as ee, Z as R, _ as Le, $ as Me, V as He, A as Xe, a0 as We, a1 as Je, a2 as Ke, a3 as Ve } from "./main-BnLtessp.js";
4
+ import { D as E, a as W, b as Ge, e as qe, f as _e, S as Qe } from "./SideDrawer-CDAoobvX.js";
5
+ import { P as ne, a as Ye, D as Ze, b as eo, h as oo } from "./handleCopyClick-BtXos0AJ.js";
6
6
  const ao = (c, i) => {
7
7
  const l = atob(c.split(",")[1]), g = new ArrayBuffer(l.length), e = new Uint8Array(g);
8
8
  for (let r = 0; r < l.length; r++)
@@ -1,7 +1,7 @@
1
1
  import { jsx as i, jsxs as r } from "react/jsx-runtime";
2
2
  import m, { useCallback as D, useMemo as h } from "react";
3
- import { p, a as g, q as w, M as l } from "./main-rJpE4hh-.js";
4
- import { S as b, D as u, a as k, b as y, c as S, d as f } from "./SideDrawer-WneDrrWG.js";
3
+ import { p, a as g, q as w, M as l } from "./main-BnLtessp.js";
4
+ import { S as b, D as u, a as k, b as y, c as S, d as f } from "./SideDrawer-CDAoobvX.js";
5
5
  const T = ({
6
6
  handleCloseModal: n
7
7
  }) => {
@@ -1,7 +1,7 @@
1
1
  import { jsxs as K, jsx as x, Fragment as Hr } from "react/jsx-runtime";
2
2
  import * as F from "react";
3
3
  import { useState as Yt, useRef as ke, useEffect as be, useMemo as Wt, useCallback as mi } from "react";
4
- import { u as Xi, P as Kn, H as xi, a as Hd, b as zd, c as Kd, d as Gd, s as po, e as Jd, f as Yd, g as fo, h as $d, i as Xd, j as mo, k as Qd, l as Zd, r as go, m as eu, n as tu, A as vo, V as bo, B as nu } from "./main-rJpE4hh-.js";
4
+ import { u as Xi, P as Kn, H as xi, a as Hd, b as zd, c as Kd, d as Gd, s as po, e as Jd, f as Yd, g as fo, h as $d, i as Xd, j as mo, k as Qd, l as Zd, r as go, m as eu, n as tu, A as vo, V as bo, B as nu } from "./main-BnLtessp.js";
5
5
  function iu(n, e) {
6
6
  return e.forEach(function(t) {
7
7
  t && typeof t != "string" && !Array.isArray(t) && Object.keys(t).forEach(function(i) {
@@ -1,7 +1,7 @@
1
1
  import { jsxs as r, jsx as s } from "react/jsx-runtime";
2
2
  import { useState as b, useEffect as x } from "react";
3
- import { x as o, a as L, p as P, u as z, aG as D, aH as I } from "./main-rJpE4hh-.js";
4
- import { S as N, D as C, a as $, b as k, e as w, f as p } from "./SideDrawer-WneDrrWG.js";
3
+ import { x as o, a as L, p as N, u as P, aM as D, aN as z } from "./main-BnLtessp.js";
4
+ import { S as I, D as C, a as $, b as k, e as w, f as p } from "./SideDrawer-CDAoobvX.js";
5
5
  o.div``;
6
6
  o.div`
7
7
  font-size: 16px;
@@ -25,7 +25,7 @@ const O = o.div`
25
25
  `, u = o.input`
26
26
  accent-color: ${({ $radioColor: i }) => i || "var(--ethora-color-primary, #0052CD)"};
27
27
  margin: 0px;
28
- `, R = o.div`
28
+ `, M = o.div`
29
29
  padding: 10px 15px;
30
30
  margin-top: 16px;
31
31
  color: ${({ type: i }) => i === "success" ? "#10b981" : "#ef4444"};
@@ -39,12 +39,12 @@ const O = o.div`
39
39
  background: ${({ type: i }) => i === "success" ? "rgba(16, 185, 129, 0.15)" : "rgba(242, 118, 107, 0.15)"};
40
40
  border-color: ${({ type: i }) => i === "success" ? "var(--ethora-color-success, #10b981)" : "var(--ethora-color-danger, #ef4444)"};
41
41
  }
42
- `, H = ({
42
+ `, B = ({
43
43
  handleCloseModal: i
44
44
  }) => {
45
- const S = L(), e = P(), { user: n, config: l } = z(
45
+ const S = L(), e = N(), { user: n, config: l } = P(
46
46
  (t) => t.chatSettingStore
47
- ), g = (t) => S(I(t)), [a, m] = b(n?.isProfileOpen), [c, v] = b(n?.isAssetsOpen), [f, y] = b(null), d = (t, A) => {
47
+ ), g = (t) => S(z(t)), [a, m] = b(n?.isProfileOpen), [c, v] = b(n?.isAssetsOpen), [f, y] = b(null), d = (t, A) => {
48
48
  y({ message: t, type: A }), setTimeout(() => y(null), 3e3);
49
49
  };
50
50
  return x(() => {
@@ -56,7 +56,7 @@ const O = o.div`
56
56
  g(t.user), d(e("notification.saved"), "success");
57
57
  }).catch(() => d(e("toast.error"), "error"));
58
58
  }, [c]), /* @__PURE__ */ r(
59
- N,
59
+ I,
60
60
  {
61
61
  title: e("settings.visibility.title"),
62
62
  onClose: i,
@@ -128,11 +128,11 @@ const O = o.div`
128
128
  /* @__PURE__ */ s(p, { children: e("settings.visibility.individualDescription") })
129
129
  ] }) }) })
130
130
  ] }),
131
- f && /* @__PURE__ */ s(R, { type: f.type, children: f.message })
131
+ f && /* @__PURE__ */ s(M, { type: f.type, children: f.message })
132
132
  ]
133
133
  }
134
134
  );
135
135
  };
136
136
  export {
137
- H as default
137
+ B as default
138
138
  };
@@ -8,6 +8,8 @@ interface MentionDropdownProps {
8
8
  onSelect: (candidate: MentionCandidate) => void;
9
9
  onShowAll: () => void;
10
10
  onHoverIndex: (index: number) => void;
11
+ /** More people are still being loaded in the background. */
12
+ loading?: boolean;
11
13
  }
12
14
  export declare const MentionDropdown: React.FC<MentionDropdownProps>;
13
15
  export default MentionDropdown;
@@ -0,0 +1,19 @@
1
+ export interface AnchorRowRect {
2
+ id: string;
3
+ top: number;
4
+ bottom: number;
5
+ }
6
+ export interface ScrollAnchor {
7
+ id: string;
8
+ /** Row top relative to the scroller's top edge. */
9
+ offset: number;
10
+ }
11
+ /**
12
+ * The row to hold still while content changes around it: the first row that
13
+ * is fully inside the viewport, or, when none is (a row taller than the
14
+ * viewport, or the viewport cuts every row), the first one that intersects it.
15
+ * `rows` must be in document order.
16
+ */
17
+ export declare function pickAnchorRow(viewTop: number, viewBottom: number, rows: AnchorRowRect[]): ScrollAnchor | null;
18
+ /** How far scrollTop must move for the anchor row to sit at its old offset. */
19
+ export declare function anchorScrollDelta(anchor: ScrollAnchor, rowTop: number, viewTop: number): number;
@@ -1,16 +1,16 @@
1
1
  import { MutableRefObject, RefObject } from 'react';
2
+ import { PendingJump } from '../../roomStore/roomsSlice';
2
3
  import { IMessage } from '../../types/types';
4
+ import { findMessageIndex } from '../../helpers/jumpThread';
5
+ export { findMessageIndex };
6
+ export declare const NEAR_LIVE_MESSAGES = 300;
3
7
  /**
4
- * Index of the message a jump names.
5
- *
6
- * By id first (message.id is the MAM stanza id for history, xmppId the client
7
- * message id). When the request has no id at all, which is common for archive
8
- * rows, by content: same text, sent within a few seconds of the same time.
8
+ * How the attempt to open a window around the target went:
9
+ * - found: the window is in the store; the list now renders it;
10
+ * - missing: the server answered and the target is not in its archive;
11
+ * - unavailable: could not ask (no archive id, request failed): page instead.
9
12
  */
10
- export declare const findMessageIndex: (messages: IMessage[], ids: string[], content?: {
11
- createdAt?: string;
12
- body?: string;
13
- }) => number;
13
+ export type WindowFetchResult = 'found' | 'missing' | 'unavailable';
14
14
  /** What the server said about one page of older history. */
15
15
  export interface OlderPage {
16
16
  /** False when the request failed or timed out. */
@@ -47,6 +47,38 @@ interface Options {
47
47
  * bottom, undoing the jump the moment the target loads.
48
48
  */
49
49
  isUserScrolledUpRef: MutableRefObject<boolean>;
50
+ /** `messages` is a jump window around an earlier target, not the live list. */
51
+ jumpWindowActive?: boolean;
52
+ /**
53
+ * Opens a window around a far target (and puts it in the store). Omitted
54
+ * where windows do not apply (threads); the paging path is used then.
55
+ */
56
+ fetchWindow?: (jump: PendingJump) => Promise<WindowFetchResult>;
57
+ /**
58
+ * Which list this instance is. A jump is fulfilled by exactly one list: the
59
+ * main list, or the thread its target is a reply in. The other instances
60
+ * stay inert for it, so one of them cannot give up (and show the archived
61
+ * card) while the owner is still working.
62
+ */
63
+ scope?: 'main' | {
64
+ threadId: string;
65
+ };
66
+ /**
67
+ * The room's messages BEFORE the main list's filter (which hides thread
68
+ * replies). Lets the main list recognise a target that is a thread reply.
69
+ */
70
+ allMessages?: IMessage[];
71
+ /**
72
+ * Opens the thread a reply target belongs to (main list only). Resolves true
73
+ * when the thread is open and owns the jump from now on.
74
+ */
75
+ resolveReply?: (jump: PendingJump, reply: IMessage) => Promise<boolean>;
76
+ /**
77
+ * The room is still opening (joining, loading its first history). While it
78
+ * is, a request that cannot be answered yet is waited out, not counted as a
79
+ * failure: the card is for "the server answered and the message is absent".
80
+ */
81
+ roomOpening?: boolean;
50
82
  }
51
83
  /**
52
84
  * Fulfils a pending "scroll to this message" request for this room.
@@ -59,5 +91,4 @@ interface Options {
59
91
  * up, bounded by MAX_HISTORY_PAGES and by the end of the archive.
60
92
  * If it cannot be reached, say so rather than leaving the tap looking dead.
61
93
  */
62
- export declare function useJumpToMessage({ roomJID, messages, visibleCount, setRenderWindow, fetchOlderPage, containerRef, historyComplete, isUserScrolledUpRef, }: Options): void;
63
- export {};
94
+ export declare function useJumpToMessage({ roomJID, messages, visibleCount, setRenderWindow, fetchOlderPage, containerRef, historyComplete, isUserScrolledUpRef, jumpWindowActive, fetchWindow, scope, allMessages, resolveReply, roomOpening, }: Options): void;
@@ -0,0 +1,29 @@
1
+ import { RefObject } from 'react';
2
+ /** The reader counts as still after this long without scrolling. */
3
+ export declare const ANCHOR_IDLE_MS = 100;
4
+ interface Options {
5
+ containerRef: RefObject<HTMLElement>;
6
+ /** The element whose height changes as rows grow. */
7
+ flowRef: RefObject<HTMLElement>;
8
+ /** Identity changes whenever the mounted rows can change. */
9
+ rows: unknown;
10
+ /** True when the reader follows the bottom: nothing is anchored then. */
11
+ isStuckToBottom: () => boolean;
12
+ }
13
+ /**
14
+ * Keeps the rows the reader is looking at perfectly still while content is
15
+ * added or resized above or below them (older history prepended, a jump
16
+ * window paged either way, the render window widened, rows trimmed).
17
+ *
18
+ * - Just before a commit that can change the rows, the anchor is captured from
19
+ * the live DOM (the render phase still sees the previous layout).
20
+ * - The layout effect puts it back before paint, by the anchor ROW's own
21
+ * movement, so a row that gained a date divider or header is absorbed too.
22
+ * - Rows keep changing height after a commit (images, embeds, waveforms).
23
+ * Whenever the content resizes and the reader has been still for
24
+ * ANCHOR_IDLE_MS, the anchor is re-applied by a ResizeObserver. The anchor
25
+ * is re-taken ANCHOR_IDLE_MS after any scroll this hook did not make (the
26
+ * reader, a jump) and dropped while that scroll is going on.
27
+ */
28
+ export declare function useScrollAnchor({ containerRef, flowRef, rows, isStuckToBottom, }: Options): void;
29
+ export {};
@@ -1,5 +1,10 @@
1
1
  import { default as React } from 'react';
2
2
  import { MessageSearchHit } from '../../../networking/api-requests/messageSearch.api';
3
+ /**
4
+ * Secondary pill button used for "Show more" and "Retry" under search
5
+ * results, in the search panel and in the room list.
6
+ */
7
+ export declare const SecondaryPillButton: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
3
8
  /**
4
9
  * What a tap on a search hit does, shared by the search panel and the room
5
10
  * list's search box: switch to the hit's room and ask it to scroll to, load
@@ -9,8 +9,6 @@ export declare const ModalContainer: import('styled-components/dist/types').ISty
9
9
  export declare const ModalTitle: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>, never>> & string;
10
10
  /** Small uppercase-weight label above a field/list inside a modal - e.g. "Select Users (max 20)". */
11
11
  export declare const ModalSectionLabel: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
12
- /** 48px-min-height row used for members/blocked-users/etc. lists inside modals. */
13
- export declare const ModalListRow: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
14
12
  export declare const ModalDescription: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, never>> & string;
15
13
  export declare const GroupContainer: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
16
14
  export declare const ModalContainerFullScreen: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('styled-components').FastOmit<import('styled-components/dist/types').Substitute<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, Omit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
@@ -24,15 +22,9 @@ export declare const HeaderRight: import('styled-components/dist/types').IStyled
24
22
  export declare const CenterContainer: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<Omit<import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>, "ref"> & {
25
23
  ref?: import('react').Ref<HTMLDivElement>;
26
24
  }, never>> & string;
27
- export declare const ProfileImage: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
28
- export declare const UserInfo: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
29
25
  export declare const UserName: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
30
- export declare const UserStatus: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
31
- export declare const BorderedContainer: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
32
- export declare const LabelData: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
33
26
  export declare const Label: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
34
27
  export declare const ActionButton: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<Omit<ButtonProps & import('react').RefAttributes<HTMLButtonElement>, "ref"> & {
35
28
  ref?: import('react').Ref<HTMLButtonElement>;
36
29
  }, never>> & string & Omit<import('react').ForwardRefExoticComponent<ButtonProps & import('react').RefAttributes<HTMLButtonElement>>, keyof import('react').Component<any, {}, any>>;
37
- export declare const EmptySection: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
38
30
  export declare const Divider: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
@@ -1,4 +1,4 @@
1
- import { x as e, z as t } from "./main-rJpE4hh-.js";
1
+ import { x as e, z as t } from "./main-BnLtessp.js";
2
2
  const i = e.div`
3
3
  display: flex;
4
4
  flex-direction: column;
@@ -1,3 +1,3 @@
1
1
  import { IMessage, RoomMember } from '../types/types';
2
- export declare const checkUniqueUsers: (messages: IMessage[]) => Promise<RoomMember[]>;
3
- export declare const checkSingleUser: (usersSet: Record<string, RoomMember>, xmppUsername: string) => Promise<RoomMember>;
2
+ export declare const checkUniqueUsers: (messages: IMessage[]) => any;
3
+ export declare const checkSingleUser: (usersSet: Record<string, RoomMember>, xmppUsername: string) => Promise<any>;
@@ -0,0 +1,10 @@
1
+ import { RoomMember } from '../types/types';
2
+ /** Stable identity of a member: normalised xmppUsername local part, else _id. */
3
+ export declare const memberKey: (m: Partial<RoomMember> | null | undefined) => string;
4
+ /**
5
+ * Drops repeated members (keeps the first occurrence, order preserved).
6
+ * The room directory endpoint can return the same user on several pages;
7
+ * duplicates would produce duplicate React keys and inflated counts.
8
+ * Members without any identity are dropped.
9
+ */
10
+ export declare const dedupeMembers: <T extends Partial<RoomMember>>(list: ReadonlyArray<T> | null | undefined) => T[];
@@ -0,0 +1,25 @@
1
+ import { IConfig } from '../types/types';
2
+ export type HistoryPreloadMode = 'staged' | 'all' | 'off';
3
+ export interface ResolvedHistoryPreload {
4
+ /**
5
+ * 'legacy' only when a host explicitly pinned
6
+ * `historyQoS.stagedPreloadEnabled: false`: the old cache catch-up path
7
+ * (updateMessagesTillLast). Everything else resolves to a public mode.
8
+ */
9
+ mode: HistoryPreloadMode | 'legacy';
10
+ /** Rooms (by recent activity) the background sweep covers. 0 = no cap. */
11
+ topRooms: number;
12
+ concurrency: number;
13
+ firstPassSize: number;
14
+ secondPassSize: number;
15
+ }
16
+ export declare const DEFAULT_PRELOAD_TOP_ROOMS = 8;
17
+ export declare const DEFAULT_PRELOAD_CONCURRENCY = 3;
18
+ export declare const TEASER_ROOM_FACTOR = 4;
19
+ /**
20
+ * One place that turns `config.historyPreload` (and the older
21
+ * `historyQoS.stagedPreload*` / `preloadTopKRooms` names, still honoured)
22
+ * into the numbers the preload sweeps use. Staged preload is the default:
23
+ * the sweep covers the top N rooms, every other room loads when it is opened.
24
+ */
25
+ export declare const resolveHistoryPreloadConfig: (config?: Pick<IConfig, "historyPreload" | "historyQoS"> | null) => ResolvedHistoryPreload;
@@ -1,4 +1,5 @@
1
1
  import { default as XmppClient } from '../networking/xmppClient';
2
+ import { IRoom } from '../types/types';
2
3
  interface HistoryPreloadSchedulerOptions {
3
4
  client: XmppClient;
4
5
  signal?: AbortSignal;
@@ -10,6 +11,8 @@ interface HistoryPreloadSchedulerOptions {
10
11
  defaultRoomJids?: string[];
11
12
  forceReload?: boolean;
12
13
  completionState?: 'done' | 'partial';
14
+ skipApiPreview?: boolean;
13
15
  }
16
+ export declare const hasApiPreview: (room?: IRoom) => boolean;
14
17
  export declare const runHistoryPreloadScheduler: (options: HistoryPreloadSchedulerOptions) => Promise<void>;
15
18
  export default runHistoryPreloadScheduler;
@@ -1,4 +1,5 @@
1
1
  import { IMessage } from '../types/types';
2
+ export declare function deepMerge(target: any, source: any): any;
2
3
  export declare function insertMessageWithDelimiter(roomMessages: Partial<IMessage>[], message: IMessage, lastViewedTimestamp: {
3
4
  toString: () => string;
4
5
  }): void;
@@ -0,0 +1,9 @@
1
+ import { IConfig } from '../types/types';
2
+ /**
3
+ * The single rule for message search. It is opt-in: the host must set
4
+ * `enableMessageSearch` AND provide an `appId` (the archive endpoint is scoped
5
+ * by app). A leftover `disableMessageSearch: true` still wins as a hard off.
6
+ * Every entry point (header button, profile entry, chat-list matches, the
7
+ * Ctrl/Cmd+F shortcut, the modal itself) goes through this helper.
8
+ */
9
+ export declare const isMessageSearchEnabled: (config?: Pick<IConfig, "enableMessageSearch" | "disableMessageSearch" | "appId"> | null) => boolean;
@@ -0,0 +1,56 @@
1
+ import { IMessage } from '../types/types';
2
+ /** How long a jump request may stay pending before it is dropped. */
3
+ export declare const JUMP_TTL_MS = 60000;
4
+ /**
5
+ * Index of the message a jump names.
6
+ *
7
+ * By id first (message.id is the MAM stanza id for history, xmppId the client
8
+ * message id). When the request has no id at all, which is common for archive
9
+ * rows, by content: same text, sent within a few seconds of the same time.
10
+ */
11
+ export declare const findMessageIndex: (messages: IMessage[], ids: string[], content?: {
12
+ createdAt?: string;
13
+ body?: string;
14
+ }) => number;
15
+ /**
16
+ * Where a jump to a thread REPLY lands, and the thread panel's parent message
17
+ * when that message is not in the room's live list.
18
+ *
19
+ * Replies never appear in the main list (it hides them unless they are also
20
+ * shown in the channel), so a jump to one has to open its parent's thread and
21
+ * highlight the reply there. Two things have to be remembered for that:
22
+ * - which list owns the jump: `at` is the pending request this entry serves,
23
+ * `parentId` the thread that owns it. The main list stays inert for a jump
24
+ * that has an owner thread, and a thread list stays inert for any jump that
25
+ * is not its own (see useJumpToMessage);
26
+ * - the parent and the replies when they exist only in a jump window or came
27
+ * from a separate fetch: the thread panel reads them from here, so it does
28
+ * not depend on the window that found them still being on screen.
29
+ *
30
+ * Kept outside redux on purpose: the room slice's thread flag lives on
31
+ * messages of the live list, which is exactly what these messages are not in.
32
+ */
33
+ export interface JumpThreadState {
34
+ roomJID: string;
35
+ parentId: string;
36
+ /** The pending request this entry serves; null for a thread opened by hand. */
37
+ at: number | null;
38
+ /** Set only when the parent is not in the room's live messages. */
39
+ parent: IMessage | null;
40
+ /** Replies known to belong to the thread beyond the live list. */
41
+ replies: IMessage[];
42
+ }
43
+ export declare const getJumpThread: () => JumpThreadState | null;
44
+ export declare const setJumpThread: (next: JumpThreadState | null) => void;
45
+ export declare const clearJumpThread: () => void;
46
+ export declare const subscribeJumpThread: (listener: () => void) => (() => void);
47
+ export declare const useJumpThread: () => JumpThreadState | null;
48
+ /** The thread that owns the jump `at`, or null when the main list does. */
49
+ export declare const ownerThreadFor: (thread: JumpThreadState | null, at: number | undefined) => string | null;
50
+ /**
51
+ * The parent id of a message that is a thread reply and nothing else, or null:
52
+ * a reply also shown in the channel is in the main list, so it needs no thread.
53
+ */
54
+ export declare const replyParentId: (message: IMessage) => string | null;
55
+ /** `a` then `b`, one entry per message id, oldest first. */
56
+ export declare const mergeById: (a: IMessage[], b: IMessage[]) => IMessage[];
@@ -0,0 +1,73 @@
1
+ import { HistoryWindowPage } from '../networking/xmppClient';
2
+ import { JumpWindow } from '../roomStore/roomsSlice';
3
+ import { IMessage } from '../types/types';
4
+ /** Messages shown above / below the target when a window opens (tunable). */
5
+ export declare const JUMP_WINDOW_BEFORE = 10;
6
+ export declare const JUMP_WINDOW_AFTER = 10;
7
+ /** Page size for loading more once the reader scrolls toward either edge. */
8
+ export declare const JUMP_WINDOW_PAGE = 20;
9
+ /** The slice of the XMPP client the window helpers need. */
10
+ export interface HistoryWindowClient {
11
+ getHistoryWindow: (chatJID: string, max: number, cursor: {
12
+ before?: number;
13
+ after?: number;
14
+ start?: string;
15
+ end?: string;
16
+ }) => Promise<HistoryWindowPage>;
17
+ }
18
+ export type JumpWindowResult =
19
+ /** The window around the target is ready to be shown. */
20
+ {
21
+ status: 'found';
22
+ window: JumpWindow;
23
+ }
24
+ /** The server answered, and the target is not in the archive. */
25
+ | {
26
+ status: 'missing';
27
+ }
28
+ /** No usable id, or a request failed: use the paging path instead. */
29
+ | {
30
+ status: 'unavailable';
31
+ };
32
+ /**
33
+ * How far apart the archive's timestamp and the transcript's may be for the
34
+ * same message. They are recorded by different components, so they are not
35
+ * identical, but never more than a moment apart.
36
+ */
37
+ export declare const CONTENT_MATCH_WINDOW_MS = 5000;
38
+ /** What a hit with no archive id can be located by. */
39
+ export interface JumpContent {
40
+ createdAt?: string;
41
+ body?: string;
42
+ }
43
+ export declare const mamIdCandidates: (ids: string[]) => string[];
44
+ /**
45
+ * Fetches about JUMP_WINDOW_BEFORE messages before the target, the target and
46
+ * about JUMP_WINDOW_AFTER after it: two MAM queries in parallel (the target
47
+ * itself comes with the "after" page, asked from one microsecond before it).
48
+ * Nothing is written to the store here.
49
+ */
50
+ export declare function loadJumpWindow(client: HistoryWindowClient, roomJID: string, ids: string[], content?: JumpContent): Promise<JumpWindowResult>;
51
+ /**
52
+ * For a hit with no usable archive id (older archive documents carry neither a
53
+ * stanza id nor a message id): ask the server for the rows within a few
54
+ * seconds of its timestamp (MAM start/end filter), find the one with the same
55
+ * text, and continue exactly as the id-based window does with that row's id.
56
+ * The server's answer is final: 'missing' only when it said the range holds no
57
+ * such row.
58
+ */
59
+ export declare function loadJumpWindowByTime(client: HistoryWindowClient, roomJID: string, content: JumpContent): Promise<JumpWindowResult>;
60
+ export interface OlderWindowPage {
61
+ messages: IMessage[];
62
+ olderCursor: number | null;
63
+ hasOlder: boolean;
64
+ }
65
+ export interface NewerWindowPage {
66
+ messages: IMessage[];
67
+ newerCursor: number | null;
68
+ hasNewer: boolean;
69
+ }
70
+ /** The page above the window; null when the request failed. */
71
+ export declare function loadOlderWindowPage(client: HistoryWindowClient, window: JumpWindow): Promise<OlderWindowPage | null>;
72
+ /** The page below the window; null when the request failed. */
73
+ export declare function loadNewerWindowPage(client: HistoryWindowClient, window: JumpWindow): Promise<NewerWindowPage | null>;
@@ -0,0 +1,26 @@
1
+ import { AppDispatch } from '../roomStore';
2
+ import { IMessage } from '../types/types';
3
+ import { HistoryWindowClient } from './jumpWindow';
4
+ export interface OpenThreadForJumpParams {
5
+ client?: HistoryWindowClient | null;
6
+ dispatch: AppDispatch;
7
+ roomJID: string;
8
+ /** The pending request this opens a thread for. */
9
+ at: number;
10
+ /** The reply the jump named. */
11
+ reply: IMessage;
12
+ /** The room's live messages, unfiltered. */
13
+ live: IMessage[];
14
+ /** Messages found alongside the reply (a window), unfiltered. */
15
+ nearby?: IMessage[];
16
+ }
17
+ /**
18
+ * Opens the thread a reply belongs to, so a jump to the reply can highlight it
19
+ * there. Resolves true when the thread is open (or about to be), false when
20
+ * the parent could not be obtained.
21
+ *
22
+ * The parent comes from the live list (the usual thread flag), from the
23
+ * messages found next to the reply, or, when it is in neither, from a window
24
+ * around the parent fetched for the purpose.
25
+ */
26
+ export declare function openThreadForJump({ client, dispatch, roomJID, at, reply, live, nearby, }: OpenThreadForJumpParams): Promise<boolean>;
@@ -61,4 +61,11 @@ export interface PdfjsLib {
61
61
  }
62
62
  /** Test seam - the module-level cache would otherwise leak between cases. */
63
63
  export declare const resetPdfjsCache: () => void;
64
- export declare const loadPdfjs: (workerSrc?: string) => Promise<PdfjsLib | null>;
64
+ /**
65
+ * `libUrl`: load pdf.js from this URL (an ES module build such as
66
+ * `pdfjs-dist/legacy/build/pdf.min.mjs` served by the host) instead of the
67
+ * copy bundled with the component. For hosts that ship the component as one
68
+ * self-contained script (the embeddable widget), where a bundled pdf.js is
69
+ * 1.7 MB that every visitor downloads whether or not a PDF ever appears.
70
+ */
71
+ export declare const loadPdfjs: (workerSrc?: string, libUrl?: string) => Promise<PdfjsLib | null>;