@sparkelf/dsh-group-chat 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -125,6 +125,10 @@ window.__ModuleLoader__.load({
125
125
  const suffix = path === void 0 || path.length === 0 ? "" : `?path=${encodeURIComponent(path)}`;
126
126
  return call(`/directories${suffix}`);
127
127
  };
128
+ const listEvents = (roomId, cursor) => {
129
+ const suffix = cursor === void 0 ? "" : `?cursor=${encodeURIComponent(cursor)}`;
130
+ return call(`/rooms/${encodeURIComponent(roomId)}/events${suffix}`);
131
+ };
128
132
  /**
129
133
  * Create a room.
130
134
  *
@@ -258,222 +262,6 @@ window.__ModuleLoader__.load({
258
262
  /** Drops a pending reply that will not be sent. */
259
263
  const clearQuote = (roomId) => call(`/rooms/${encodeURIComponent(roomId)}/quote`, { method: "DELETE" });
260
264
  //#endregion
261
- //#region \0dsh-css:/root/projects/dsh-plugins-plus/packages/group-chat/src/client/MessageSearch.module.css.mjs
262
- const css$10 = ".NBSFYa_root{box-sizing:border-box;flex-direction:column;width:100%;min-width:0;display:flex}.NBSFYa_bar{align-items:center;gap:6px;min-width:0;min-height:28px;padding:0 12px;display:flex}.NBSFYa_toggle{width:24px;height:24px;color:var(--dsw-alias-label-secondary,inherit);cursor:pointer;opacity:.75;background:0 0;border:none;border-radius:6px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.NBSFYa_toggle:hover,.NBSFYa_toggle[aria-expanded=true]{opacity:1;background:var(--dsw-alias-bg-l2,#ffffff14)}.NBSFYa_toggle:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,currentcolor);outline-offset:1px}.NBSFYa_input{background:var(--dsw-alias-bg-l2,#ffffff0f);min-width:0;height:24px;color:var(--dsw-alias-label-primary,inherit);border:none;border-radius:6px;outline:none;flex:auto;padding:0 6px;font-size:12px}.NBSFYa_input::placeholder{color:var(--dsw-alias-label-secondary,inherit);opacity:.7}.NBSFYa_results{flex-direction:column;gap:2px;max-height:240px;padding:2px 8px 4px;display:flex;overflow-y:auto}.NBSFYa_hint{color:var(--dsw-alias-label-secondary,inherit);opacity:.75;margin:6px 4px;font-size:12px;line-height:16px}.NBSFYa_hit{width:100%;color:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:6px;flex-direction:column;gap:1px;padding:5px 8px;display:flex}.NBSFYa_hit:hover,.NBSFYa_hit:focus-visible{background:var(--dsw-alias-bg-l2,#ffffff14);outline:none}.NBSFYa_hitHead{min-width:0;color:var(--dsw-alias-label-secondary,inherit);align-items:baseline;gap:6px;font-size:11px;line-height:14px;display:flex}.NBSFYa_hitRoom{flex:none;font-weight:500}.NBSFYa_hitAuthor{text-overflow:ellipsis;white-space:nowrap;opacity:.8;min-width:0;overflow:hidden}.NBSFYa_hitText{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:12px;line-height:16px;display:block;overflow:hidden}.NBSFYa_mark{background:var(--dsw-alias-bg-brand-weak,#ffd66659);color:inherit;border-radius:2px;padding:0;font-weight:600}";
263
- const tagId$10 = "@sparkelf/dsh-group-chat/MessageSearch.module.css";
264
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$10) + "]") === null) {
265
- const tag = document.createElement("style");
266
- tag.dataset.plugin = "@sparkelf/dsh-group-chat";
267
- tag.dataset.pluginCss = tagId$10;
268
- tag.textContent = css$10;
269
- document.head.appendChild(tag);
270
- }
271
- var MessageSearch_module_css_default = {
272
- "results": "NBSFYa_results",
273
- "bar": "NBSFYa_bar",
274
- "hitHead": "NBSFYa_hitHead",
275
- "hitRoom": "NBSFYa_hitRoom",
276
- "toggle": "NBSFYa_toggle",
277
- "hint": "NBSFYa_hint",
278
- "hit": "NBSFYa_hit",
279
- "mark": "NBSFYa_mark",
280
- "root": "NBSFYa_root",
281
- "input": "NBSFYa_input",
282
- "hitAuthor": "NBSFYa_hitAuthor",
283
- "hitText": "NBSFYa_hitText"
284
- };
285
- //#endregion
286
- //#region src/client/MessageSearch.tsx
287
- /**
288
- * The message search box and its result list.
289
- *
290
- * A separate surface from the room filter above it: that one narrows the list of rooms by name,
291
- * this one finds text inside them. Combining the two would mean one box whose meaning changes
292
- * with what it matched, which is the sort of ambiguity that makes a search feel broken.
293
- *
294
- * The panel is a list seat in the sidebar footer, below the room rows: results are transient and
295
- * belong to the moment the reader is looking for something, not beside the rooms they live in.
296
- *
297
- * @module @sparkelf/dsh-group-chat/client/MessageSearch
298
- */
299
- /** How long to wait after the last keystroke before asking the server. */
300
- const DEBOUNCE_MS = 250;
301
- /**
302
- * Renders the search field and, once something was typed, the hits.
303
- *
304
- * Results are debounced and the newest request wins: typing quickly issues several searches, and
305
- * an early one resolving late would replace the results of a later, more specific query.
306
- */
307
- /**
308
- * The hit text with the matched words marked.
309
- *
310
- * Splitting on the query rather than rendering the raw string gives the reader the one thing a
311
- * result list has to offer: where in a long message the words actually are. Case is preserved
312
- * from the source text; only the comparison is case-insensitive.
313
- */
314
- const highlighted = (text, query) => {
315
- const needle = query.trim();
316
- if (needle.length === 0) return text;
317
- const parts = [];
318
- const lower = text.toLowerCase();
319
- const target = needle.toLowerCase();
320
- let from = 0;
321
- let at = lower.indexOf(target);
322
- let key = 0;
323
- while (at !== -1) {
324
- if (at > from) parts.push(text.slice(from, at));
325
- parts.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("mark", {
326
- className: MessageSearch_module_css_default["mark"],
327
- children: text.slice(at, at + needle.length)
328
- }, key));
329
- key += 1;
330
- from = at + needle.length;
331
- at = lower.indexOf(target, from);
332
- }
333
- if (from < text.length) parts.push(text.slice(from));
334
- return parts;
335
- };
336
- const MessageSearch = (props) => {
337
- const { t, onOpen } = props;
338
- const [open, setOpen] = (0, react.useState)(false);
339
- const [query, setQuery] = (0, react.useState)("");
340
- const [hits, setHits] = (0, react.useState)([]);
341
- const [busy, setBusy] = (0, react.useState)(false);
342
- const input = (0, react.useRef)(null);
343
- /** Increments per issued search, so a stale response can be recognized and dropped. */
344
- const issued = (0, react.useRef)(0);
345
- (0, react.useEffect)(() => {
346
- if (!open) return;
347
- const trimmed = query.trim();
348
- if (trimmed.length === 0) {
349
- setHits([]);
350
- setBusy(false);
351
- return;
352
- }
353
- const ticket = issued.current + 1;
354
- issued.current = ticket;
355
- setBusy(true);
356
- const timer = setTimeout(() => {
357
- searchMessages(trimmed).then((found) => {
358
- if (issued.current === ticket) setHits(found);
359
- }).catch(() => {
360
- if (issued.current === ticket) setHits([]);
361
- }).finally(() => {
362
- if (issued.current === ticket) setBusy(false);
363
- });
364
- }, DEBOUNCE_MS);
365
- return () => {
366
- clearTimeout(timer);
367
- };
368
- }, [query, open]);
369
- (0, react.useEffect)(() => {
370
- if (!open) return;
371
- const onKey = (event) => {
372
- if (event.key !== "Escape") return;
373
- setQuery("");
374
- setHits([]);
375
- setOpen(false);
376
- };
377
- document.addEventListener("keydown", onKey);
378
- return () => {
379
- document.removeEventListener("keydown", onKey);
380
- };
381
- }, [open]);
382
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
383
- className: MessageSearch_module_css_default["root"],
384
- "data-group-chat-message-search": "",
385
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
386
- className: MessageSearch_module_css_default["bar"],
387
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
388
- type: "button",
389
- className: MessageSearch_module_css_default["toggle"],
390
- "aria-label": t("searchMessages"),
391
- "aria-expanded": open,
392
- title: t("searchMessages"),
393
- onClick: () => {
394
- setOpen((was) => {
395
- const next = !was;
396
- if (next) requestAnimationFrame(() => {
397
- input.current?.focus();
398
- });
399
- else {
400
- setQuery("");
401
- setHits([]);
402
- }
403
- return next;
404
- });
405
- },
406
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
407
- width: "14",
408
- height: "14",
409
- viewBox: "0 0 16 16",
410
- fill: "none",
411
- stroke: "currentColor",
412
- strokeWidth: "1.4",
413
- strokeLinecap: "round",
414
- strokeLinejoin: "round",
415
- "aria-hidden": "true",
416
- children: [
417
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
418
- cx: "7",
419
- cy: "7",
420
- r: "4.2"
421
- }),
422
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m10.2 10.2 3 3" }),
423
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M4.2 5.4h5.6" }),
424
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M4.2 7.4h4" })
425
- ]
426
- })
427
- }), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
428
- ref: input,
429
- className: MessageSearch_module_css_default["input"],
430
- type: "search",
431
- value: query,
432
- placeholder: t("searchMessagesPlaceholder"),
433
- "aria-label": t("searchMessages"),
434
- onChange: (event) => {
435
- setQuery(event.target.value);
436
- }
437
- }) : null]
438
- }), open && query.trim().length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
439
- className: MessageSearch_module_css_default["results"],
440
- role: "listbox",
441
- "aria-label": t("searchMessages"),
442
- children: busy && hits.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
443
- className: MessageSearch_module_css_default["hint"],
444
- children: t("searching")
445
- }) : hits.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
446
- className: MessageSearch_module_css_default["hint"],
447
- children: t("searchMessagesEmpty")
448
- }) : hits.map((hit) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
449
- type: "button",
450
- role: "option",
451
- "aria-selected": false,
452
- className: MessageSearch_module_css_default["hit"],
453
- onClick: () => {
454
- onOpen(hit.roomId, hit.eventId);
455
- setQuery("");
456
- setHits([]);
457
- setOpen(false);
458
- },
459
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
460
- className: MessageSearch_module_css_default["hitHead"],
461
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
462
- className: MessageSearch_module_css_default["hitRoom"],
463
- children: hit.roomName
464
- }), hit.authorName === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
465
- className: MessageSearch_module_css_default["hitAuthor"],
466
- children: hit.authorName
467
- })]
468
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
469
- className: MessageSearch_module_css_default["hitText"],
470
- children: highlighted(hit.text, query)
471
- })]
472
- }, `${hit.roomId}:${hit.eventId}`))
473
- }) : null]
474
- });
475
- };
476
- //#endregion
477
265
  //#region src/client/rows.ts
478
266
  /**
479
267
  * The decisions the plugin's components make without a browser.
@@ -724,11 +512,11 @@ window.__ModuleLoader__.load({
724
512
  document.head.appendChild(tag);
725
513
  }
726
514
  var Avatar_module_css_default = {
727
- "over": "Ohch6W_over",
728
- "sm": "Ohch6W_sm",
729
- "avatar": "Ohch6W_avatar",
730
515
  "md": "Ohch6W_md",
731
- "stack": "Ohch6W_stack"
516
+ "avatar": "Ohch6W_avatar",
517
+ "stack": "Ohch6W_stack",
518
+ "sm": "Ohch6W_sm",
519
+ "over": "Ohch6W_over"
732
520
  };
733
521
  //#endregion
734
522
  //#region src/client/Avatar.tsx
@@ -768,12 +556,12 @@ window.__ModuleLoader__.load({
768
556
  document.head.appendChild(tag);
769
557
  }
770
558
  var Picker_module_css_default = {
559
+ "box": "sKjJ-a_box",
560
+ "rowActive": "sKjJ-a_rowActive",
771
561
  "secondary": "sKjJ-a_secondary",
772
562
  "note": "sKjJ-a_note",
773
- "list": "sKjJ-a_list",
774
563
  "row": "sKjJ-a_row",
775
- "rowActive": "sKjJ-a_rowActive",
776
- "box": "sKjJ-a_box",
564
+ "list": "sKjJ-a_list",
777
565
  "label": "sKjJ-a_label"
778
566
  };
779
567
  //#endregion
@@ -947,11 +735,11 @@ window.__ModuleLoader__.load({
947
735
  document.head.appendChild(tag);
948
736
  }
949
737
  var PresetSelect_module_css_default = {
950
- "row": "xjnmxG_row",
951
- "triggerLabel": "xjnmxG_triggerLabel",
952
- "trigger": "xjnmxG_trigger",
953
738
  "description": "xjnmxG_description",
954
- "name": "xjnmxG_name"
739
+ "name": "xjnmxG_name",
740
+ "trigger": "xjnmxG_trigger",
741
+ "triggerLabel": "xjnmxG_triggerLabel",
742
+ "row": "xjnmxG_row"
955
743
  };
956
744
  //#endregion
957
745
  //#region src/client/PresetSelect.tsx
@@ -1209,23 +997,23 @@ window.__ModuleLoader__.load({
1209
997
  document.head.appendChild(tag);
1210
998
  }
1211
999
  var CreateRoomDialog_module_css_default = {
1212
- "switches": "Z3w8WW_switches",
1213
- "hint": "Z3w8WW_hint",
1000
+ "notice": "Z3w8WW_notice",
1001
+ "warn": "Z3w8WW_warn",
1002
+ "triggerExtra": "Z3w8WW_triggerExtra",
1003
+ "label": "Z3w8WW_label",
1214
1004
  "field": "Z3w8WW_field",
1005
+ "pillActive": "Z3w8WW_pillActive",
1006
+ "footer": "Z3w8WW_footer",
1007
+ "switches": "Z3w8WW_switches",
1215
1008
  "policyRow": "Z3w8WW_policyRow",
1216
- "body": "Z3w8WW_body",
1009
+ "memberRow": "Z3w8WW_memberRow",
1217
1010
  "memberList": "Z3w8WW_memberList",
1218
1011
  "memberBadge": "Z3w8WW_memberBadge",
1219
- "pillActive": "Z3w8WW_pillActive",
1220
- "notice": "Z3w8WW_notice",
1221
- "triggerExtra": "Z3w8WW_triggerExtra",
1012
+ "hint": "Z3w8WW_hint",
1222
1013
  "error": "Z3w8WW_error",
1223
- "label": "Z3w8WW_label",
1224
- "memberRow": "Z3w8WW_memberRow",
1225
- "footer": "Z3w8WW_footer",
1226
- "warn": "Z3w8WW_warn",
1227
1014
  "pill": "Z3w8WW_pill",
1228
- "memberName": "Z3w8WW_memberName"
1015
+ "memberName": "Z3w8WW_memberName",
1016
+ "body": "Z3w8WW_body"
1229
1017
  };
1230
1018
  //#endregion
1231
1019
  //#region src/client/CreateRoomDialog.tsx
@@ -1492,28 +1280,28 @@ window.__ModuleLoader__.load({
1492
1280
  document.head.appendChild(tag);
1493
1281
  }
1494
1282
  var InviteDialog_module_css_default = {
1283
+ "check": "r4uCba_check",
1284
+ "dialog": "r4uCba_dialog",
1285
+ "list": "r4uCba_list",
1495
1286
  "checkHidden": "r4uCba_checkHidden",
1496
1287
  "row": "r4uCba_row",
1497
- "inviteSpin": "r4uCba_inviteSpin",
1498
- "content": "r4uCba_content",
1288
+ "chip": "r4uCba_chip",
1499
1289
  "chipRemove": "r4uCba_chipRemove",
1290
+ "rowName": "r4uCba_rowName",
1500
1291
  "error": "r4uCba_error",
1292
+ "spinner": "r4uCba_spinner",
1293
+ "chips": "r4uCba_chips",
1501
1294
  "rowHandle": "r4uCba_rowHandle",
1502
1295
  "errorRow": "r4uCba_errorRow",
1503
- "search": "r4uCba_search",
1296
+ "visuallyHidden": "r4uCba_visuallyHidden",
1297
+ "inviteSpin": "r4uCba_inviteSpin",
1298
+ "content": "r4uCba_content",
1299
+ "note": "r4uCba_note",
1504
1300
  "searchRow": "r4uCba_searchRow",
1301
+ "search": "r4uCba_search",
1505
1302
  "field": "r4uCba_field",
1506
- "chips": "r4uCba_chips",
1507
- "spinner": "r4uCba_spinner",
1508
1303
  "chipName": "r4uCba_chipName",
1509
- "rowSelected": "r4uCba_rowSelected",
1510
- "rowName": "r4uCba_rowName",
1511
- "visuallyHidden": "r4uCba_visuallyHidden",
1512
- "chip": "r4uCba_chip",
1513
- "note": "r4uCba_note",
1514
- "dialog": "r4uCba_dialog",
1515
- "check": "r4uCba_check",
1516
- "list": "r4uCba_list"
1304
+ "rowSelected": "r4uCba_rowSelected"
1517
1305
  };
1518
1306
  //#endregion
1519
1307
  //#region src/client/RoomDialogs.tsx
@@ -2120,7 +1908,7 @@ window.__ModuleLoader__.load({
2120
1908
  }
2121
1909
  //#endregion
2122
1910
  //#region \0dsh-css:/root/projects/dsh-plugins-plus/packages/group-chat/src/client/SidebarRooms.module.css.mjs
2123
- const css$4 = ".s0QgKq_root{--dsh-session-list-edge-inset:var(--dsh-sidebar-inline-padding,12px);--dsh-session-list-scrollbar-width:5px;--dsh-session-list-scrollbar-offset:2px;box-sizing:border-box;flex-direction:column;flex:auto;width:100%;min-width:0;min-height:0;max-height:20vh;display:flex;position:relative}.s0QgKq_resizer{z-index:1;cursor:row-resize;touch-action:none;background:0 0;height:6px;position:absolute;top:-3px;left:0;right:0}.s0QgKq_resizer:after{content:\"\";background:var(--dsw-alias-border-l1,var(--dsw-alias-separator-primary));opacity:0;border-radius:1px;height:1px;transition:opacity .12s;position:absolute;top:3px;left:8px;right:8px}.s0QgKq_root:hover .s0QgKq_resizer:after,.s0QgKq_resizer:focus-visible:after{opacity:1}.s0QgKq_resizer:focus-visible{outline:none}.s0QgKq_resizer:focus-visible:after{background:var(--dsw-alias-brand-primary,var(--dsw-alias-label-primary));height:2px}.s0QgKq_sectionHeader{box-sizing:border-box;border-radius:var(--dsw-radius-md);height:36px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:flex-end;align-items:center;gap:4px;margin-bottom:4px;margin-right:-4px;padding-left:4px;display:flex;overflow:hidden}.s0QgKq_sectionLabel{white-space:nowrap;flex:none;min-width:0;max-width:45%;line-height:20px;overflow:hidden}.s0QgKq_searchSlot{box-sizing:border-box;flex:1;align-items:center;min-width:0;max-width:28px;margin-left:auto;padding-left:0;display:flex}.s0QgKq_searchSlotExpanded{box-sizing:border-box;flex:1;align-items:center;min-width:0;max-width:100%;margin-left:auto;display:flex}.s0QgKq_search,.s0QgKq_searchExpanded{box-sizing:border-box;border-radius:var(--dsw-radius-sm);width:100%;height:28px;color:var(--dsw-alias-label-secondary);cursor:text;background:0 0;border:none;flex:none;align-items:center;margin:0;padding:0;display:flex;overflow:hidden}.s0QgKq_searchExpanded{border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);width:calc(100% + 4px);height:30px;color:var(--dsw-alias-label-caption);margin-inline:-2px;padding:0 4px 0 0}.s0QgKq_iconButton{border-radius:var(--dsw-radius-sm);width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.s0QgKq_iconButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.s0QgKq_iconButton:focus-visible,.s0QgKq_searchButton:focus-visible,.s0QgKq_clearButton:focus-visible{outline:var(--dsw-focus-ring-width,2px) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:-2px}.s0QgKq_searchButton{border-radius:var(--dsw-radius-sm);width:28px;height:28px;color:inherit;cursor:pointer;background:0 0;border:none;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.s0QgKq_searchExpanded .s0QgKq_searchButton{width:28px;height:30px}.s0QgKq_searchButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.s0QgKq_searchExpanded .s0QgKq_searchButton:hover{background:0 0}.s0QgKq_searchInput{width:0;min-width:0;color:var(--dsw-alias-label-primary);opacity:0;pointer-events:none;transition:opacity .12s var(--ds-ease-in-out);background:0 0;border:none;outline:none;flex:1;padding:0;font-size:13px;line-height:18px}.s0QgKq_searchExpanded .s0QgKq_searchInput{opacity:1;pointer-events:auto;margin-left:-2px}.s0QgKq_searchInput::placeholder{color:var(--dsw-alias-label-tertiary)}.s0QgKq_clearButton{border-radius:var(--dsw-radius-sm);width:24px;height:24px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.s0QgKq_clearButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.s0QgKq_headerActions{flex:none;align-items:center;gap:4px;display:flex}.s0QgKq_viewWrap{display:flex;position:relative}.s0QgKq_listArea{min-height:0;margin-left:-4px;margin-right:calc(-1 * var(--dsh-session-list-edge-inset));flex-direction:column;flex:1;padding-left:4px;display:flex;position:relative}.s0QgKq_list{min-height:0;max-height:100%;margin-left:-4px;margin-right:var(--dsh-session-list-scrollbar-offset);padding-left:4px;padding-right:calc(var(--dsh-session-list-edge-inset) - var(--dsh-session-list-scrollbar-width) - var(--dsh-session-list-scrollbar-offset));scrollbar-gutter:stable;padding-bottom:8px;overflow-y:auto}.s0QgKq_flatList{margin:0;padding:0;list-style:none}.s0QgKq_flatList>*+*{margin-top:2px}.s0QgKq_sessionRow,.s0QgKq_sessionRowSelected{box-sizing:border-box;border-radius:var(--dsw-radius-sm);width:100%;height:32px;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;padding:0 8px;font-size:14px;display:flex}.s0QgKq_sessionRow:hover,.s0QgKq_sessionRowSelected{background:var(--dsw-alias-interactive-bg-hover)}.s0QgKq_rowIcon{width:16px;color:var(--dsw-alias-label-secondary);flex:none;justify-content:center;align-items:center;display:flex}.s0QgKq_title{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.s0QgKq_time{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;font-size:12px;line-height:17px}.s0QgKq_unread{background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-interactive-bg-hover));min-width:18px;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;text-align:center;border-radius:9px;flex:none;padding:0 5px;font-size:11px;font-weight:600;line-height:17px}.s0QgKq_unreadMentioned{background:var(--dsw-alias-state-business-primary);min-width:18px;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;text-align:center;border-radius:9px;flex:none;padding:0 5px;font-size:11px;font-weight:600;line-height:17px}.s0QgKq_empty{color:var(--dsw-alias-label-tertiary);margin:0;padding:16px 12px;font-size:13px}.s0QgKq_emptyState{color:var(--dsw-alias-label-tertiary);text-align:center;flex-direction:column;align-items:center;gap:8px;margin-top:80px;padding:0 12px;font-size:13px;line-height:20px;display:flex}.s0QgKq_emptyState>svg{color:var(--dsw-alias-label-caption);margin-bottom:4px}.s0QgKq_fade{left:0;right:var(--dsh-session-list-edge-inset);background:linear-gradient(to bottom, transparent, var(--dsw-specific-sidebar-fill));pointer-events:none;height:24px;position:absolute;bottom:0}.s0QgKq_menuLayer{z-index:60;max-height:calc(100vh - 16px);position:fixed;overflow-y:auto}.s0QgKq_menuInline{z-index:30;position:absolute;top:32px;right:0}.s0QgKq_menu{border:1px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1,var(--dsw-specific-sidebar-fill));min-width:200px;padding:4px;position:relative;box-shadow:0 6px 20px #0000002e}.s0QgKq_menuHeading{color:var(--dsw-alias-label-tertiary);padding:4px 8px 2px;font-size:11px;line-height:16px;display:block}.s0QgKq_menuItem{border-radius:var(--dsw-radius-sm);width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;padding:6px 8px;font-size:13px;display:flex}.s0QgKq_menuItem:hover{background:var(--dsw-alias-interactive-bg-hover)}.s0QgKq_check{color:var(--dsw-alias-state-business-primary);margin-left:auto}.s0QgKq_visuallyHidden{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.s0QgKq_rowWrap{position:relative}.s0QgKq_menuRename{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1,var(--dsw-specific-sidebar-fill));min-width:240px;padding:8px;box-shadow:0 6px 20px #0000002e}.s0QgKq_menuRename .s0QgKq_menuHeading{padding:0 0 6px}.s0QgKq_menuInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-sm);appearance:none;background:var(--dsw-alias-bg-base);width:100%;color:var(--dsw-alias-label-primary);font:inherit;outline:none;margin:2px 0 6px;padding:6px 8px;font-size:13px;line-height:20px}.s0QgKq_menuInput:focus-visible{border-color:var(--dsw-alias-state-business-primary)}.s0QgKq_menuInput::placeholder{color:var(--dsw-alias-label-tertiary)}.s0QgKq_menuActions{justify-content:flex-end;gap:6px;padding-top:2px;display:flex}.s0QgKq_menuConfirm{box-sizing:border-box;border-radius:var(--dsw-radius-sm);background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);font:inherit;cursor:pointer;border:1px solid #0000;padding:5px 12px;font-size:12px;line-height:18px}.s0QgKq_menuConfirm:hover:not(:disabled){filter:brightness(1.06)}.s0QgKq_menuConfirm:disabled{opacity:.5;cursor:default}.s0QgKq_menuCancel{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-sm);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;padding:5px 12px;font-size:12px;line-height:18px}.s0QgKq_menuCancel:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.s0QgKq_menuItem:disabled{opacity:.5;cursor:default}.s0QgKq_discoverSection{border-top:1px solid var(--dsw-alias-border-l3);margin-top:8px;padding-top:8px}.s0QgKq_discoverHeading{color:var(--dsw-alias-label-tertiary);margin:0 0 4px;padding:0 12px;font-size:11px;line-height:16px}.s0QgKq_discoverRow{border-radius:var(--dsw-radius-sm);color:var(--dsw-alias-label-primary);align-items:center;gap:8px;padding:4px 12px;font-size:13px;line-height:18px;display:flex}.s0QgKq_discoverRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.s0QgKq_discoverName{text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0;overflow:hidden}.s0QgKq_discoverMeta{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px}.s0QgKq_joinButton{border:1px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-sm);color:var(--dsw-alias-state-business-primary);font:inherit;cursor:pointer;background:0 0;flex:none;padding:2px 10px;font-size:12px}.s0QgKq_joinButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.s0QgKq_joinButton:disabled{opacity:.5;cursor:default}.s0QgKq_leaveBody{flex-direction:column;gap:8px;min-width:0;display:flex}.s0QgKq_leaveCopy{color:var(--dsw-alias-label-primary);margin:0;font-size:14px;line-height:22px}.s0QgKq_leaveRoomName{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;font-size:14px;line-height:22px}.s0QgKq_leaveRoomName strong{font-weight:600}.s0QgKq_leaveError{color:var(--dsw-alias-state-error-primary,#f85149);margin:0;font-size:12px;line-height:17px}.s0QgKq_footer{justify-content:flex-end;gap:8px;display:flex}.s0QgKq_leaveConfirmDanger{background:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary)}.s0QgKq_leaveConfirmDanger.s0QgKq_leaveConfirmDanger{color:var(--dsw-alias-label-primary)}.s0QgKq_leaveConfirmDanger:hover:not(:disabled){background:var(--dsw-alias-state-error-primary);filter:brightness(1.08)}.s0QgKq_leaveConfirmDanger:disabled{opacity:.5}";
1911
+ const css$4 = ".s0QgKq_root{--dsh-session-list-edge-inset:var(--dsh-sidebar-inline-padding,12px);--dsh-session-list-scrollbar-width:5px;--dsh-session-list-scrollbar-offset:2px;box-sizing:border-box;flex-direction:column;flex:auto;width:100%;min-width:0;min-height:0;max-height:20vh;display:flex;position:relative}.s0QgKq_resizer{z-index:1;cursor:row-resize;touch-action:none;background:0 0;height:6px;position:absolute;top:-3px;left:0;right:0}.s0QgKq_resizer:after{content:\"\";background:var(--dsw-alias-border-l1,var(--dsw-alias-separator-primary));opacity:0;border-radius:1px;height:1px;transition:opacity .12s;position:absolute;top:3px;left:8px;right:8px}.s0QgKq_root:hover .s0QgKq_resizer:after,.s0QgKq_resizer:focus-visible:after{opacity:1}.s0QgKq_resizer:focus-visible{outline:none}.s0QgKq_resizer:focus-visible:after{background:var(--dsw-alias-brand-primary,var(--dsw-alias-label-primary));height:2px}.s0QgKq_sectionHeader{box-sizing:border-box;border-radius:var(--dsw-radius-md);height:36px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:flex-end;align-items:center;gap:4px;margin-bottom:4px;margin-right:-4px;padding-left:4px;display:flex;overflow:hidden}.s0QgKq_sectionLabel{white-space:nowrap;flex:none;min-width:0;max-width:45%;line-height:20px;overflow:hidden}.s0QgKq_searchSlot{box-sizing:border-box;flex:1;align-items:center;min-width:0;max-width:28px;margin-left:auto;padding-left:0;display:flex}.s0QgKq_searchSlotExpanded{box-sizing:border-box;flex:1;align-items:center;min-width:0;max-width:100%;margin-left:auto;padding-right:4px;display:flex}.s0QgKq_search,.s0QgKq_searchExpanded{box-sizing:border-box;border-radius:var(--dsw-radius-sm);width:100%;height:28px;color:var(--dsw-alias-label-secondary);cursor:text;background:0 0;border:none;flex:none;align-items:center;margin:0;padding:0;display:flex;overflow:hidden}.s0QgKq_searchExpanded{border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);width:100%;height:30px;color:var(--dsw-alias-label-caption);margin-inline:0;padding:0 4px 0 0}.s0QgKq_iconButton{border-radius:var(--dsw-radius-sm);width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.s0QgKq_iconButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.s0QgKq_iconButton:focus-visible,.s0QgKq_searchButton:focus-visible,.s0QgKq_clearButton:focus-visible{outline:var(--dsw-focus-ring-width,2px) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:-2px}.s0QgKq_searchButton{border-radius:var(--dsw-radius-sm);width:28px;height:28px;color:inherit;cursor:pointer;background:0 0;border:none;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.s0QgKq_searchExpanded .s0QgKq_searchButton{width:28px;height:30px}.s0QgKq_searchButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.s0QgKq_searchExpanded .s0QgKq_searchButton:hover{background:0 0}.s0QgKq_searchInput{width:0;min-width:0;color:var(--dsw-alias-label-primary);opacity:0;pointer-events:none;transition:opacity .12s var(--ds-ease-in-out);background:0 0;border:none;outline:none;flex:1;padding:0;font-size:13px;line-height:18px}.s0QgKq_searchExpanded .s0QgKq_searchInput{opacity:1;pointer-events:auto;margin-left:-2px}.s0QgKq_searchInput::placeholder{color:var(--dsw-alias-label-tertiary)}.s0QgKq_clearButton{border-radius:var(--dsw-radius-sm);width:24px;height:24px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.s0QgKq_clearButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.s0QgKq_headerActions{flex:none;align-items:center;gap:4px;display:flex}.s0QgKq_viewWrap{display:flex;position:relative}.s0QgKq_listArea{min-height:0;margin-left:-4px;margin-right:calc(-1 * var(--dsh-session-list-edge-inset));flex-direction:column;flex:1;padding-left:4px;display:flex;position:relative}.s0QgKq_list{min-height:0;max-height:100%;margin-left:-4px;margin-right:var(--dsh-session-list-scrollbar-offset);padding-left:4px;padding-right:calc(var(--dsh-session-list-edge-inset) - var(--dsh-session-list-scrollbar-width) - var(--dsh-session-list-scrollbar-offset));scrollbar-gutter:stable;padding-bottom:8px;overflow-y:auto}.s0QgKq_flatList{margin:0;padding:0;list-style:none}.s0QgKq_flatList>*+*{margin-top:2px}.s0QgKq_sessionRow,.s0QgKq_sessionRowSelected{box-sizing:border-box;border-radius:var(--dsw-radius-sm);width:100%;height:32px;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;padding:0 8px;font-size:14px;display:flex}.s0QgKq_sessionRow:hover,.s0QgKq_sessionRowSelected{background:var(--dsw-alias-interactive-bg-hover)}.s0QgKq_rowIcon{width:16px;color:var(--dsw-alias-label-secondary);flex:none;justify-content:center;align-items:center;display:flex}.s0QgKq_title{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.s0QgKq_time{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;font-size:12px;line-height:17px}.s0QgKq_unread{background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-interactive-bg-hover));min-width:18px;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;text-align:center;border-radius:9px;flex:none;padding:0 5px;font-size:11px;font-weight:600;line-height:17px}.s0QgKq_unreadMentioned{background:var(--dsw-alias-state-business-primary);min-width:18px;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;text-align:center;border-radius:9px;flex:none;padding:0 5px;font-size:11px;font-weight:600;line-height:17px}.s0QgKq_empty{color:var(--dsw-alias-label-tertiary);margin:0;padding:16px 12px;font-size:13px}.s0QgKq_emptyState{color:var(--dsw-alias-label-tertiary);text-align:center;flex-direction:column;align-items:center;gap:8px;margin-top:80px;padding:0 12px;font-size:13px;line-height:20px;display:flex}.s0QgKq_emptyState>svg{color:var(--dsw-alias-label-caption);margin-bottom:4px}.s0QgKq_fade{left:0;right:var(--dsh-session-list-edge-inset);background:linear-gradient(to bottom, transparent, var(--dsw-specific-sidebar-fill));pointer-events:none;height:24px;position:absolute;bottom:0}.s0QgKq_menuLayer{z-index:60;max-height:calc(100vh - 16px);position:fixed;overflow-y:auto}.s0QgKq_menuInline{z-index:30;position:absolute;top:32px;right:0}.s0QgKq_menu{border:1px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1,var(--dsw-specific-sidebar-fill));min-width:200px;padding:4px;position:relative;box-shadow:0 6px 20px #0000002e}.s0QgKq_menuHeading{color:var(--dsw-alias-label-tertiary);padding:4px 8px 2px;font-size:11px;line-height:16px;display:block}.s0QgKq_menuItem{border-radius:var(--dsw-radius-sm);width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;padding:6px 8px;font-size:13px;display:flex}.s0QgKq_menuItem:hover{background:var(--dsw-alias-interactive-bg-hover)}.s0QgKq_check{color:var(--dsw-alias-state-business-primary);margin-left:auto}.s0QgKq_visuallyHidden{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.s0QgKq_rowWrap{position:relative}.s0QgKq_menuRename{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1,var(--dsw-specific-sidebar-fill));min-width:240px;padding:8px;box-shadow:0 6px 20px #0000002e}.s0QgKq_menuRename .s0QgKq_menuHeading{padding:0 0 6px}.s0QgKq_menuInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-sm);appearance:none;background:var(--dsw-alias-bg-base);width:100%;color:var(--dsw-alias-label-primary);font:inherit;outline:none;margin:2px 0 6px;padding:6px 8px;font-size:13px;line-height:20px}.s0QgKq_menuInput:focus-visible{border-color:var(--dsw-alias-state-business-primary)}.s0QgKq_menuInput::placeholder{color:var(--dsw-alias-label-tertiary)}.s0QgKq_menuActions{justify-content:flex-end;gap:6px;padding-top:2px;display:flex}.s0QgKq_menuConfirm{box-sizing:border-box;border-radius:var(--dsw-radius-sm);background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);font:inherit;cursor:pointer;border:1px solid #0000;padding:5px 12px;font-size:12px;line-height:18px}.s0QgKq_menuConfirm:hover:not(:disabled){filter:brightness(1.06)}.s0QgKq_menuConfirm:disabled{opacity:.5;cursor:default}.s0QgKq_menuCancel{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-sm);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;padding:5px 12px;font-size:12px;line-height:18px}.s0QgKq_menuCancel:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.s0QgKq_menuItem:disabled{opacity:.5;cursor:default}.s0QgKq_discoverSection{border-top:1px solid var(--dsw-alias-border-l3);margin-top:8px;padding-top:8px}.s0QgKq_discoverHeading{color:var(--dsw-alias-label-tertiary);margin:0 0 4px;padding:0 12px;font-size:11px;line-height:16px}.s0QgKq_discoverRow{border-radius:var(--dsw-radius-sm);color:var(--dsw-alias-label-primary);align-items:center;gap:8px;padding:4px 12px;font-size:13px;line-height:18px;display:flex}.s0QgKq_discoverRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.s0QgKq_discoverName{text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0;overflow:hidden}.s0QgKq_discoverMeta{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px}.s0QgKq_joinButton{border:1px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-sm);color:var(--dsw-alias-state-business-primary);font:inherit;cursor:pointer;background:0 0;flex:none;padding:2px 10px;font-size:12px}.s0QgKq_joinButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.s0QgKq_joinButton:disabled{opacity:.5;cursor:default}.s0QgKq_leaveBody{flex-direction:column;gap:8px;min-width:0;display:flex}.s0QgKq_leaveCopy{color:var(--dsw-alias-label-primary);margin:0;font-size:14px;line-height:22px}.s0QgKq_leaveRoomName{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;font-size:14px;line-height:22px}.s0QgKq_leaveRoomName strong{font-weight:600}.s0QgKq_leaveError{color:var(--dsw-alias-state-error-primary,#f85149);margin:0;font-size:12px;line-height:17px}.s0QgKq_footer{justify-content:flex-end;gap:8px;display:flex}.s0QgKq_leaveConfirmDanger{background:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary)}.s0QgKq_leaveConfirmDanger.s0QgKq_leaveConfirmDanger{color:var(--dsw-alias-label-primary)}.s0QgKq_leaveConfirmDanger:hover:not(:disabled){background:var(--dsw-alias-state-error-primary);filter:brightness(1.08)}.s0QgKq_leaveConfirmDanger:disabled{opacity:.5}.s0QgKq_hitList{flex-direction:column;flex:none;gap:2px;max-height:45%;margin-bottom:4px;display:flex;overflow-y:auto}.s0QgKq_hitHint{color:var(--dsw-alias-label-tertiary);margin:2px 8px;font-size:12px;line-height:16px}.s0QgKq_hit{border-radius:var(--dsw-radius-sm);width:100%;color:inherit;text-align:left;cursor:pointer;background:0 0;border:none;flex-direction:column;gap:1px;padding:5px 8px;display:flex}.s0QgKq_hit:hover,.s0QgKq_hit:focus-visible{background:var(--dsw-alias-interactive-bg-hover);outline:none}.s0QgKq_hitHead{min-width:0;color:var(--dsw-alias-label-tertiary);align-items:baseline;gap:6px;font-size:11px;line-height:14px;display:flex}.s0QgKq_hitRoom{flex:none;font-weight:500}.s0QgKq_hitAuthor{text-overflow:ellipsis;white-space:nowrap;opacity:.8;min-width:0;overflow:hidden}.s0QgKq_hitText{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:12px;line-height:16px;display:block;overflow:hidden}.s0QgKq_mark{background:var(--dsw-alias-bg-brand-weak,#ffd66659);color:inherit;border-radius:2px;padding:0;font-weight:600}";
2124
1912
  const tagId$4 = "@sparkelf/dsh-group-chat/SidebarRooms.module.css";
2125
1913
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
2126
1914
  const tag = document.createElement("style");
@@ -2130,58 +1918,66 @@ window.__ModuleLoader__.load({
2130
1918
  document.head.appendChild(tag);
2131
1919
  }
2132
1920
  var SidebarRooms_module_css_default = {
2133
- "clearButton": "s0QgKq_clearButton",
2134
- "resizer": "s0QgKq_resizer",
2135
- "time": "s0QgKq_time",
2136
- "menuActions": "s0QgKq_menuActions",
2137
- "discoverHeading": "s0QgKq_discoverHeading",
2138
- "leaveConfirmDanger": "s0QgKq_leaveConfirmDanger",
2139
- "iconButton": "s0QgKq_iconButton",
2140
- "discoverRow": "s0QgKq_discoverRow",
2141
- "rowWrap": "s0QgKq_rowWrap",
2142
- "menuConfirm": "s0QgKq_menuConfirm",
2143
- "searchButton": "s0QgKq_searchButton",
2144
- "headerActions": "s0QgKq_headerActions",
2145
- "empty": "s0QgKq_empty",
2146
- "unreadMentioned": "s0QgKq_unreadMentioned",
1921
+ "searchInput": "s0QgKq_searchInput",
1922
+ "joinButton": "s0QgKq_joinButton",
2147
1923
  "sectionHeader": "s0QgKq_sectionHeader",
2148
- "searchExpanded": "s0QgKq_searchExpanded",
2149
- "rowIcon": "s0QgKq_rowIcon",
2150
- "leaveCopy": "s0QgKq_leaveCopy",
1924
+ "menuRename": "s0QgKq_menuRename",
2151
1925
  "footer": "s0QgKq_footer",
1926
+ "listArea": "s0QgKq_listArea",
1927
+ "clearButton": "s0QgKq_clearButton",
1928
+ "discoverMeta": "s0QgKq_discoverMeta",
1929
+ "search": "s0QgKq_search",
1930
+ "leaveCopy": "s0QgKq_leaveCopy",
1931
+ "hit": "s0QgKq_hit",
1932
+ "rowIcon": "s0QgKq_rowIcon",
1933
+ "fade": "s0QgKq_fade",
1934
+ "searchSlotExpanded": "s0QgKq_searchSlotExpanded",
1935
+ "discoverRow": "s0QgKq_discoverRow",
1936
+ "hitText": "s0QgKq_hitText",
1937
+ "menuItem": "s0QgKq_menuItem",
1938
+ "hitRoom": "s0QgKq_hitRoom",
2152
1939
  "menuInput": "s0QgKq_menuInput",
2153
- "discoverName": "s0QgKq_discoverName",
2154
- "unread": "s0QgKq_unread",
2155
- "menuInline": "s0QgKq_menuInline",
2156
- "menuCancel": "s0QgKq_menuCancel",
2157
- "menuRename": "s0QgKq_menuRename",
2158
- "leaveBody": "s0QgKq_leaveBody",
1940
+ "empty": "s0QgKq_empty",
1941
+ "hitList": "s0QgKq_hitList",
1942
+ "discoverHeading": "s0QgKq_discoverHeading",
1943
+ "sessionRowSelected": "s0QgKq_sessionRowSelected",
1944
+ "flatList": "s0QgKq_flatList",
2159
1945
  "leaveRoomName": "s0QgKq_leaveRoomName",
2160
- "discoverSection": "s0QgKq_discoverSection",
2161
- "root": "s0QgKq_root",
2162
- "fade": "s0QgKq_fade",
2163
- "searchInput": "s0QgKq_searchInput",
1946
+ "menuCancel": "s0QgKq_menuCancel",
1947
+ "hitHead": "s0QgKq_hitHead",
1948
+ "menuInline": "s0QgKq_menuInline",
1949
+ "hitAuthor": "s0QgKq_hitAuthor",
2164
1950
  "sessionRow": "s0QgKq_sessionRow",
2165
- "menuLayer": "s0QgKq_menuLayer",
2166
- "discoverMeta": "s0QgKq_discoverMeta",
1951
+ "root": "s0QgKq_root",
2167
1952
  "menu": "s0QgKq_menu",
2168
- "joinButton": "s0QgKq_joinButton",
1953
+ "unreadMentioned": "s0QgKq_unreadMentioned",
1954
+ "rowWrap": "s0QgKq_rowWrap",
1955
+ "menuActions": "s0QgKq_menuActions",
2169
1956
  "leaveError": "s0QgKq_leaveError",
2170
- "search": "s0QgKq_search",
1957
+ "headerActions": "s0QgKq_headerActions",
2171
1958
  "check": "s0QgKq_check",
2172
1959
  "list": "s0QgKq_list",
1960
+ "title": "s0QgKq_title",
1961
+ "time": "s0QgKq_time",
1962
+ "unread": "s0QgKq_unread",
1963
+ "leaveBody": "s0QgKq_leaveBody",
1964
+ "menuLayer": "s0QgKq_menuLayer",
1965
+ "searchExpanded": "s0QgKq_searchExpanded",
1966
+ "discoverSection": "s0QgKq_discoverSection",
1967
+ "menuHeading": "s0QgKq_menuHeading",
1968
+ "discoverName": "s0QgKq_discoverName",
1969
+ "mark": "s0QgKq_mark",
1970
+ "menuConfirm": "s0QgKq_menuConfirm",
2173
1971
  "sectionLabel": "s0QgKq_sectionLabel",
2174
- "searchSlot": "s0QgKq_searchSlot",
1972
+ "iconButton": "s0QgKq_iconButton",
2175
1973
  "emptyState": "s0QgKq_emptyState",
2176
- "searchSlotExpanded": "s0QgKq_searchSlotExpanded",
2177
- "listArea": "s0QgKq_listArea",
2178
- "flatList": "s0QgKq_flatList",
2179
- "sessionRowSelected": "s0QgKq_sessionRowSelected",
2180
- "menuHeading": "s0QgKq_menuHeading",
2181
- "title": "s0QgKq_title",
2182
- "menuItem": "s0QgKq_menuItem",
1974
+ "searchSlot": "s0QgKq_searchSlot",
2183
1975
  "viewWrap": "s0QgKq_viewWrap",
2184
- "visuallyHidden": "s0QgKq_visuallyHidden"
1976
+ "hitHint": "s0QgKq_hitHint",
1977
+ "visuallyHidden": "s0QgKq_visuallyHidden",
1978
+ "resizer": "s0QgKq_resizer",
1979
+ "searchButton": "s0QgKq_searchButton",
1980
+ "leaveConfirmDanger": "s0QgKq_leaveConfirmDanger"
2185
1981
  };
2186
1982
  //#endregion
2187
1983
  //#region src/client/SidebarRooms.tsx
@@ -2220,6 +2016,34 @@ window.__ModuleLoader__.load({
2220
2016
  * @param props - the injected copy resolver and the shared room store.
2221
2017
  * @returns the section header plus the flat room list.
2222
2018
  */
2019
+ /**
2020
+ * The hit text with the matched words marked.
2021
+ *
2022
+ * Splitting on the query gives the reader the one thing a result row has to offer: where in a
2023
+ * long message the words are. Case comes from the source text; only the comparison folds case.
2024
+ */
2025
+ const markQuery = (text, query) => {
2026
+ const needle = query.trim();
2027
+ if (needle.length === 0) return text;
2028
+ const parts = [];
2029
+ const lower = text.toLowerCase();
2030
+ const target = needle.toLowerCase();
2031
+ let from = 0;
2032
+ let at = lower.indexOf(target);
2033
+ let key = 0;
2034
+ while (at !== -1) {
2035
+ if (at > from) parts.push(text.slice(from, at));
2036
+ parts.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("mark", {
2037
+ className: SidebarRooms_module_css_default["mark"],
2038
+ children: text.slice(at, at + needle.length)
2039
+ }, key));
2040
+ key += 1;
2041
+ from = at + needle.length;
2042
+ at = lower.indexOf(target, from);
2043
+ }
2044
+ if (from < text.length) parts.push(text.slice(from));
2045
+ return parts;
2046
+ };
2223
2047
  function SidebarRooms(props) {
2224
2048
  const { t, tPreset, store } = props;
2225
2049
  const { rooms, activeRoomId, failure, searchQuery, discoverable } = (0, react.useSyncExternalStore)(store.subscribe, store.getState, store.getState);
@@ -2230,6 +2054,44 @@ window.__ModuleLoader__.load({
2230
2054
  const [joining, setJoining] = (0, react.useState)(void 0);
2231
2055
  const searchInput = (0, react.useRef)(null);
2232
2056
  /**
2057
+ * Opens the room a hit belongs to and scrolls to that message.
2058
+ *
2059
+ * The conversation is still loading when this fires, so the row is not in the DOM yet: poll
2060
+ * for the anchor instead of guessing one delay, and give up quietly rather than scrolling to
2061
+ * a stranger's message.
2062
+ */
2063
+ const openHit = (hit) => {
2064
+ store.open(hit.roomId);
2065
+ store.setSearch("");
2066
+ setSearchExpanded(false);
2067
+ if (typeof document === "undefined") return;
2068
+ let attempts = 0;
2069
+ const look = () => {
2070
+ const node = document.querySelector(`[data-group-chat-message="${hit.eventId}"]`);
2071
+ if (node !== null) {
2072
+ node.scrollIntoView({
2073
+ block: "center",
2074
+ behavior: "smooth"
2075
+ });
2076
+ return;
2077
+ }
2078
+ attempts += 1;
2079
+ if (attempts < 40) window.setTimeout(look, 250);
2080
+ };
2081
+ window.setTimeout(look, 400);
2082
+ };
2083
+ /**
2084
+ * Message hits for the same box the room rows are filtered by.
2085
+ *
2086
+ * One field, two questions: the rows below answer "which room is this" and this list answers
2087
+ * "where is this said". Two separate boxes made the reader choose which kind of search they
2088
+ * wanted before they knew what they were looking for.
2089
+ */
2090
+ const [hits, setHits] = (0, react.useState)([]);
2091
+ const [searching, setSearching] = (0, react.useState)(false);
2092
+ /** Issue counter so a slow query cannot overwrite the results of a later one. */
2093
+ const searchTicket = (0, react.useRef)(0);
2094
+ /**
2233
2095
  * Height of this region, in pixels, once the user has dragged it.
2234
2096
  *
2235
2097
  * `undefined` until either the saved value arrives or a drag happens: the region then keeps
@@ -2297,6 +2159,36 @@ window.__ModuleLoader__.load({
2297
2159
  document.addEventListener("pointerup", onUp);
2298
2160
  document.addEventListener("pointercancel", onUp);
2299
2161
  };
2162
+ /**
2163
+ * Message search, driven by the header box.
2164
+ *
2165
+ * Debounced and latest-wins: typing issues several queries, and an early one resolving late
2166
+ * would replace the results of a later, more specific one.
2167
+ */
2168
+ (0, react.useEffect)(() => {
2169
+ if (!searchExpanded) return;
2170
+ const trimmed = searchQuery.trim();
2171
+ if (trimmed.length === 0) {
2172
+ setHits([]);
2173
+ setSearching(false);
2174
+ return;
2175
+ }
2176
+ const ticket = searchTicket.current + 1;
2177
+ searchTicket.current = ticket;
2178
+ setSearching(true);
2179
+ const timer = setTimeout(() => {
2180
+ searchMessages(trimmed).then((found) => {
2181
+ if (searchTicket.current === ticket) setHits(found);
2182
+ }).catch(() => {
2183
+ if (searchTicket.current === ticket) setHits([]);
2184
+ }).finally(() => {
2185
+ if (searchTicket.current === ticket) setSearching(false);
2186
+ });
2187
+ }, 250);
2188
+ return () => {
2189
+ clearTimeout(timer);
2190
+ };
2191
+ }, [searchQuery, searchExpanded]);
2300
2192
  (0, react.useEffect)(() => {
2301
2193
  if (!searchExpanded) return;
2302
2194
  const onDown = (event) => {
@@ -2457,27 +2349,36 @@ window.__ModuleLoader__.load({
2457
2349
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2458
2350
  className: SidebarRooms_module_css_default.listArea,
2459
2351
  children: [
2460
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MessageSearch, {
2461
- t,
2462
- onOpen: (roomId, eventId) => {
2463
- store.open(roomId);
2464
- if (typeof document === "undefined") return;
2465
- let attempts = 0;
2466
- const look = () => {
2467
- const node = document.querySelector(`[data-group-chat-message="${eventId}"]`);
2468
- if (node !== null) {
2469
- node.scrollIntoView({
2470
- block: "center",
2471
- behavior: "smooth"
2472
- });
2473
- return;
2474
- }
2475
- attempts += 1;
2476
- if (attempts < 40) window.setTimeout(look, 250);
2477
- };
2478
- window.setTimeout(look, 400);
2479
- }
2480
- }),
2352
+ searchExpanded && query.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2353
+ className: SidebarRooms_module_css_default.hitList,
2354
+ role: "listbox",
2355
+ "aria-label": t("search"),
2356
+ children: searching && hits.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2357
+ className: SidebarRooms_module_css_default.hitHint,
2358
+ children: t("searching")
2359
+ }) : hits.length === 0 ? null : hits.map((hit) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2360
+ type: "button",
2361
+ role: "option",
2362
+ "aria-selected": false,
2363
+ className: SidebarRooms_module_css_default.hit,
2364
+ onClick: () => {
2365
+ openHit(hit);
2366
+ },
2367
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2368
+ className: SidebarRooms_module_css_default.hitHead,
2369
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2370
+ className: SidebarRooms_module_css_default.hitRoom,
2371
+ children: hit.roomName
2372
+ }), hit.authorName === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2373
+ className: SidebarRooms_module_css_default.hitAuthor,
2374
+ children: hit.authorName
2375
+ })]
2376
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2377
+ className: SidebarRooms_module_css_default.hitText,
2378
+ children: markQuery(hit.text, searchQuery)
2379
+ })]
2380
+ }, `${hit.roomId}:${hit.eventId}`))
2381
+ }) : null,
2481
2382
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2482
2383
  className: SidebarRooms_module_css_default.list,
2483
2384
  children: [
@@ -3138,20 +3039,20 @@ window.__ModuleLoader__.load({
3138
3039
  document.head.appendChild(tag);
3139
3040
  }
3140
3041
  var MessageSide_module_css_default = {
3141
- "rowActionsSelf": "KXabfq_rowActionsSelf",
3142
- "author": "KXabfq_author",
3143
- "selfBody": "KXabfq_selfBody",
3144
- "rowActions": "KXabfq_rowActions",
3145
- "quoteBar": "KXabfq_quoteBar",
3146
3042
  "rowBody": "KXabfq_rowBody",
3147
- "quoteMark": "KXabfq_quoteMark",
3148
- "quoteText": "KXabfq_quoteText",
3149
- "replyButton": "KXabfq_replyButton",
3043
+ "selfBody": "KXabfq_selfBody",
3150
3044
  "otherRow": "KXabfq_otherRow",
3045
+ "authorName": "KXabfq_authorName",
3151
3046
  "quoteBody": "KXabfq_quoteBody",
3047
+ "quoteBar": "KXabfq_quoteBar",
3152
3048
  "quoteAuthor": "KXabfq_quoteAuthor",
3153
- "authorName": "KXabfq_authorName",
3154
- "selfRow": "KXabfq_selfRow"
3049
+ "selfRow": "KXabfq_selfRow",
3050
+ "rowActions": "KXabfq_rowActions",
3051
+ "replyButton": "KXabfq_replyButton",
3052
+ "quoteMark": "KXabfq_quoteMark",
3053
+ "rowActionsSelf": "KXabfq_rowActionsSelf",
3054
+ "author": "KXabfq_author",
3055
+ "quoteText": "KXabfq_quoteText"
3155
3056
  };
3156
3057
  //#endregion
3157
3058
  //#region src/client/MessageSide.tsx
@@ -3439,46 +3340,46 @@ window.__ModuleLoader__.load({
3439
3340
  document.head.appendChild(tag);
3440
3341
  }
3441
3342
  var MembersPanel_module_css_default = {
3442
- "filePicker": "VeQVAa_filePicker",
3443
3343
  "sectionLabel": "VeQVAa_sectionLabel",
3444
- "linkButton": "VeQVAa_linkButton",
3445
- "row": "VeQVAa_row",
3344
+ "notice": "VeQVAa_notice",
3345
+ "crumbGroup": "VeQVAa_crumbGroup",
3446
3346
  "fileSize": "VeQVAa_fileSize",
3447
- "crumbs": "VeQVAa_crumbs",
3448
- "fileIcon": "VeQVAa_fileIcon",
3347
+ "hint": "VeQVAa_hint",
3449
3348
  "preview": "VeQVAa_preview",
3450
- "searchToggle": "VeQVAa_searchToggle",
3451
- "crumb": "VeQVAa_crumb",
3452
- "editorFooter": "VeQVAa_editorFooter",
3453
- "previewClose": "VeQVAa_previewClose",
3454
- "root": "VeQVAa_root",
3455
- "error": "VeQVAa_error",
3456
- "sectionToggle": "VeQVAa_sectionToggle",
3457
- "unavailable": "VeQVAa_unavailable",
3349
+ "announcementText": "VeQVAa_announcementText",
3458
3350
  "editor": "VeQVAa_editor",
3459
- "previewTitle": "VeQVAa_previewTitle",
3460
- "previewImage": "VeQVAa_previewImage",
3351
+ "search": "VeQVAa_search",
3352
+ "fileButton": "VeQVAa_fileButton",
3353
+ "selfTag": "VeQVAa_selfTag",
3354
+ "row": "VeQVAa_row",
3355
+ "root": "VeQVAa_root",
3356
+ "editorFooter": "VeQVAa_editorFooter",
3357
+ "list": "VeQVAa_list",
3358
+ "filePicker": "VeQVAa_filePicker",
3461
3359
  "previewBody": "VeQVAa_previewBody",
3462
3360
  "count": "VeQVAa_count",
3463
- "crumbSep": "VeQVAa_crumbSep",
3464
3361
  "sectionBody": "VeQVAa_sectionBody",
3465
- "notice": "VeQVAa_notice",
3466
- "textarea": "VeQVAa_textarea",
3467
- "selfTag": "VeQVAa_selfTag",
3468
- "hint": "VeQVAa_hint",
3469
- "refresh": "VeQVAa_refresh",
3470
- "section": "VeQVAa_section",
3362
+ "sectionHeader": "VeQVAa_sectionHeader",
3363
+ "previewImage": "VeQVAa_previewImage",
3364
+ "previewHeader": "VeQVAa_previewHeader",
3365
+ "sectionToggle": "VeQVAa_sectionToggle",
3366
+ "crumbSep": "VeQVAa_crumbSep",
3367
+ "linkButton": "VeQVAa_linkButton",
3471
3368
  "ownerTag": "VeQVAa_ownerTag",
3472
- "caret": "VeQVAa_caret",
3473
- "crumbGroup": "VeQVAa_crumbGroup",
3474
- "fileButton": "VeQVAa_fileButton",
3369
+ "textarea": "VeQVAa_textarea",
3370
+ "crumb": "VeQVAa_crumb",
3475
3371
  "name": "VeQVAa_name",
3476
- "previewHeader": "VeQVAa_previewHeader",
3477
- "search": "VeQVAa_search",
3478
- "list": "VeQVAa_list",
3479
- "announcementText": "VeQVAa_announcementText",
3372
+ "unavailable": "VeQVAa_unavailable",
3480
3373
  "remove": "VeQVAa_remove",
3481
- "sectionHeader": "VeQVAa_sectionHeader"
3374
+ "previewTitle": "VeQVAa_previewTitle",
3375
+ "refresh": "VeQVAa_refresh",
3376
+ "caret": "VeQVAa_caret",
3377
+ "fileIcon": "VeQVAa_fileIcon",
3378
+ "section": "VeQVAa_section",
3379
+ "error": "VeQVAa_error",
3380
+ "searchToggle": "VeQVAa_searchToggle",
3381
+ "crumbs": "VeQVAa_crumbs",
3382
+ "previewClose": "VeQVAa_previewClose"
3482
3383
  };
3483
3384
  //#endregion
3484
3385
  //#region src/client/MembersPanel.tsx
@@ -4101,10 +4002,10 @@ window.__ModuleLoader__.load({
4101
4002
  document.head.appendChild(tag);
4102
4003
  }
4103
4004
  var GuideEntry_module_css_default = {
4104
- "title": "_0Vnsuq_title",
4105
4005
  "icon": "_0Vnsuq_icon",
4106
4006
  "entry": "_0Vnsuq_entry",
4107
4007
  "description": "_0Vnsuq_description",
4008
+ "title": "_0Vnsuq_title",
4108
4009
  "text": "_0Vnsuq_text"
4109
4010
  };
4110
4011
  //#endregion
@@ -4172,13 +4073,13 @@ window.__ModuleLoader__.load({
4172
4073
  document.head.appendChild(tag);
4173
4074
  }
4174
4075
  var QuoteComposer_module_css_default = {
4076
+ "text": "AK6KxW_text",
4077
+ "dismiss": "AK6KxW_dismiss",
4175
4078
  "button": "AK6KxW_button",
4176
- "mark": "AK6KxW_mark",
4177
- "body": "AK6KxW_body",
4178
- "bar": "AK6KxW_bar",
4179
4079
  "author": "AK6KxW_author",
4180
- "dismiss": "AK6KxW_dismiss",
4181
- "text": "AK6KxW_text"
4080
+ "body": "AK6KxW_body",
4081
+ "mark": "AK6KxW_mark",
4082
+ "bar": "AK6KxW_bar"
4182
4083
  };
4183
4084
  //#endregion
4184
4085
  //#region src/client/QuoteComposer.tsx
@@ -4237,6 +4138,135 @@ window.__ModuleLoader__.load({
4237
4138
  });
4238
4139
  };
4239
4140
  //#endregion
4141
+ //#region src/client/messageReference.ts
4142
+ /**
4143
+ * Room messages as `@` references in the composer.
4144
+ *
4145
+ * Registering a trigger source is the one supported way a plugin adds something to the `@`
4146
+ * menu, and the only way to get an official inline reference: the pipeline turns a pick into
4147
+ * an atomic chip, and the codec decides what that chip becomes for the model. Drawing a
4148
+ * separate quote bar would mean a second, unofficial representation of the same idea.
4149
+ *
4150
+ * A chip carries an id; the words are resolved through this module's cache because the codec
4151
+ * only ever receives `ref`. The cache is bounded to the messages listed most recently, which
4152
+ * is the same window the menu offers.
4153
+ *
4154
+ * @module @sparkelf/dsh-group-chat/client/messageReference
4155
+ */
4156
+ /** Unique source name; duplicate `(trigger, name)` pairs throw at registration. */
4157
+ const SOURCE_NAME = "@sparkelf/dsh-group-chat/message";
4158
+ /** How many messages the menu offers at once. */
4159
+ const MAX_CANDIDATES = 20;
4160
+ /** How much of a message the menu row and the chip label show. */
4161
+ const LABEL_CHARS = 28;
4162
+ /**
4163
+ * Reference id → what it points at.
4164
+ *
4165
+ * `ref` is `${roomId}:${messageId}` so it stays readable in storage and unique across rooms;
4166
+ * the words ride beside it because the codec is synchronous about identity and only receives
4167
+ * the id.
4168
+ */
4169
+ const resolved = /* @__PURE__ */ new Map();
4170
+ /** The text of a message body, whether it arrived as blocks or as one plain string. */
4171
+ const textOf = (content) => {
4172
+ if (typeof content === "string") return content.replace(/\s+/g, " ").trim();
4173
+ if (!Array.isArray(content)) return "";
4174
+ const parts = [];
4175
+ for (const block of content) {
4176
+ if (typeof block !== "object" || block === null) continue;
4177
+ const record = block;
4178
+ if (record.type === "text" && typeof record.text === "string") parts.push(record.text);
4179
+ }
4180
+ return parts.join(" ").replace(/\s+/g, " ").trim();
4181
+ };
4182
+ /** One line, cut to `LABEL_CHARS` with an ellipsis. */
4183
+ const shorten = (text) => text.length > LABEL_CHARS ? `${text.slice(0, 27)}…` : text;
4184
+ /** What one message row shows and what a pick would insert. */
4185
+ const rowOf = (roomId, record) => {
4186
+ const data = record.event.data;
4187
+ if (data === void 0) return void 0;
4188
+ const source = data["source"];
4189
+ const rowId = typeof source?.messageId === "string" && source.messageId.length > 0 ? source.messageId : typeof data["id"] === "string" ? data["id"] : record.id;
4190
+ const text = textOf(data["content"]);
4191
+ if (text.length === 0) return void 0;
4192
+ const authorName = typeof source?.memberName === "string" && source.memberName.length > 0 ? source.memberName : void 0;
4193
+ const label = `${authorName ?? "消息"}:${shorten(text)}`;
4194
+ return {
4195
+ ref: `${roomId}:${rowId}`,
4196
+ name: label,
4197
+ description: text.length > 60 ? `${text.slice(0, 59)}…` : text,
4198
+ resolved: {
4199
+ label,
4200
+ text,
4201
+ ...authorName === void 0 ? {} : { authorName }
4202
+ }
4203
+ };
4204
+ };
4205
+ /**
4206
+ * Registers the room-message reference source.
4207
+ *
4208
+ * @param inputTriggers - the trigger pipeline service (`ctx.get('inputTriggers')`).
4209
+ * @param store - room store, read for the room the composer is writing into.
4210
+ * @returns the disposer.
4211
+ */
4212
+ const registerMessageSource = (inputTriggers, store) => {
4213
+ const source = {
4214
+ trigger: "@",
4215
+ name: SOURCE_NAME,
4216
+ order: 30,
4217
+ showGroupTitle: true,
4218
+ async candidates(_session, request) {
4219
+ const roomId = store.getState().activeRoomId;
4220
+ if (roomId === void 0) return [];
4221
+ const page = await listEvents(roomId);
4222
+ const needle = request.query.trim().toLowerCase();
4223
+ const out = [];
4224
+ for (const record of [...page.events].reverse()) {
4225
+ if (request.signal.aborted) break;
4226
+ const row = rowOf(roomId, record);
4227
+ if (row === void 0) continue;
4228
+ if (needle.length > 0 && !row.resolved.text.toLowerCase().includes(needle)) continue;
4229
+ resolved.set(row.ref, row.resolved);
4230
+ out.push({
4231
+ name: row.name,
4232
+ label: row.name,
4233
+ description: row.description,
4234
+ icon: "session",
4235
+ value: row.ref
4236
+ });
4237
+ if (out.length >= MAX_CANDIDATES) break;
4238
+ }
4239
+ return out;
4240
+ },
4241
+ onPick(pick) {
4242
+ const ref = pick.candidate.value;
4243
+ if (ref === void 0) return void 0;
4244
+ const found = resolved.get(ref);
4245
+ if (found === void 0) return void 0;
4246
+ return { insert: {
4247
+ source: SOURCE_NAME,
4248
+ ref,
4249
+ label: found.label,
4250
+ appearance: "session",
4251
+ clipboardText: `@${found.label}`
4252
+ } };
4253
+ },
4254
+ codec: {
4255
+ clipboardText: (ref) => {
4256
+ const found = resolved.get(ref);
4257
+ return found === void 0 ? ref : `@${found.label}`;
4258
+ },
4259
+ serialize: (ref) => {
4260
+ const found = resolved.get(ref);
4261
+ if (found === void 0) return Promise.resolve(ref);
4262
+ const speaker = found.authorName === void 0 ? "" : `${found.authorName}:`;
4263
+ return Promise.resolve(`> ${speaker}${found.text}`);
4264
+ }
4265
+ }
4266
+ };
4267
+ return inputTriggers.registerSource(source);
4268
+ };
4269
+ //#endregion
4240
4270
  //#region src/client/locales.ts
4241
4271
  /**
4242
4272
  * Group-chat copy, in the shape every locale-backed DSH client plugin uses: one
@@ -4257,7 +4287,7 @@ window.__ModuleLoader__.load({
4257
4287
  roomName: "Room name",
4258
4288
  create: "Create",
4259
4289
  search: "Search rooms",
4260
- searchPlaceholder: "Search rooms…",
4290
+ searchPlaceholder: "Search rooms or messages…",
4261
4291
  searchClear: "Clear search",
4262
4292
  searchEmpty: "No room matches",
4263
4293
  discoverHeading: "Rooms you can join",
@@ -4408,7 +4438,7 @@ window.__ModuleLoader__.load({
4408
4438
  roomName: "群聊名称",
4409
4439
  create: "创建",
4410
4440
  search: "搜索群聊",
4411
- searchPlaceholder: "搜索群聊…",
4441
+ searchPlaceholder: "搜索群聊或消息…",
4412
4442
  searchClear: "清除搜索",
4413
4443
  searchEmpty: "无匹配结果",
4414
4444
  discoverHeading: "可以加入的群聊",
@@ -4835,6 +4865,8 @@ window.__ModuleLoader__.load({
4835
4865
  release();
4836
4866
  };
4837
4867
  });
4868
+ const inputTriggers = ctx.get("inputTriggers");
4869
+ if (inputTriggers !== void 0) ctx.effect(() => registerMessageSource(inputTriggers, store));
4838
4870
  ctx.effect(() => ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
4839
4871
  name: "conversation.input.dock",
4840
4872
  id: QUOTE_DOCK_ID,