@refraction-ui/react 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -32660,6 +32660,7 @@ function createConversation(config = {}) {
32660
32660
  const messagesByConv = /* @__PURE__ */ new Map();
32661
32661
  let activeConversationId = config.activeConversationId ?? null;
32662
32662
  let openThreadRootId = null;
32663
+ let replyTarget = null;
32663
32664
  let status = "idle";
32664
32665
  let error = null;
32665
32666
  let abortController = null;
@@ -32681,6 +32682,7 @@ function createConversation(config = {}) {
32681
32682
  activeConversationId,
32682
32683
  messages: activeConversationId ? messagesByConv.get(activeConversationId) ?? [] : [],
32683
32684
  openThreadRootId,
32685
+ replyTarget,
32684
32686
  threadingMode,
32685
32687
  status,
32686
32688
  error
@@ -32777,6 +32779,7 @@ function createConversation(config = {}) {
32777
32779
  newConversation(opts) {
32778
32780
  const conversation = createConversationInternal(opts ?? {});
32779
32781
  openThreadRootId = null;
32782
+ replyTarget = null;
32780
32783
  emit2();
32781
32784
  return conversation;
32782
32785
  },
@@ -32784,6 +32787,7 @@ function createConversation(config = {}) {
32784
32787
  if (!conversations.has(conversationId) || activeConversationId === conversationId) return;
32785
32788
  activeConversationId = conversationId;
32786
32789
  openThreadRootId = null;
32790
+ replyTarget = null;
32787
32791
  emit2();
32788
32792
  },
32789
32793
  deleteConversation(conversationId) {
@@ -32793,6 +32797,7 @@ function createConversation(config = {}) {
32793
32797
  if (activeConversationId === conversationId) {
32794
32798
  activeConversationId = orderedConversations()[0]?.id ?? null;
32795
32799
  openThreadRootId = null;
32800
+ replyTarget = null;
32796
32801
  }
32797
32802
  emit2();
32798
32803
  },
@@ -32830,6 +32835,7 @@ function createConversation(config = {}) {
32830
32835
  const next = list.filter((m2) => !removeIds.has(m2.id));
32831
32836
  messagesByConv.set(activeConversationId, next);
32832
32837
  if (openThreadRootId && removeIds.has(openThreadRootId)) openThreadRootId = null;
32838
+ if (replyTarget && removeIds.has(replyTarget)) replyTarget = openThreadRootId;
32833
32839
  emit2();
32834
32840
  },
32835
32841
  react(messageId, emoji) {
@@ -32860,6 +32866,7 @@ function createConversation(config = {}) {
32860
32866
  const conversationId = ensureActiveConversation(opts);
32861
32867
  const list = messagesByConv.get(conversationId);
32862
32868
  const parentId = opts?.replyTo ? rootIdOf(list, opts.replyTo) : void 0;
32869
+ const replyToId = opts?.replyTo;
32863
32870
  const isFirstRoot = !parentId && selectRoots(list).length === 0;
32864
32871
  const userMsg = {
32865
32872
  id: generateId("rfr-msg"),
@@ -32870,6 +32877,7 @@ function createConversation(config = {}) {
32870
32877
  timestamp: /* @__PURE__ */ new Date(),
32871
32878
  status: "sent",
32872
32879
  parentId,
32880
+ replyToId,
32873
32881
  attachments: opts?.attachments,
32874
32882
  metadata: opts?.metadata
32875
32883
  };
@@ -32926,11 +32934,20 @@ function createConversation(config = {}) {
32926
32934
  },
32927
32935
  openThread(rootId) {
32928
32936
  openThreadRootId = rootId;
32937
+ replyTarget = rootId;
32938
+ emit2();
32939
+ },
32940
+ replyTo(messageId) {
32941
+ if (!activeConversationId) return;
32942
+ const list = messagesByConv.get(activeConversationId);
32943
+ openThreadRootId = rootIdOf(list, messageId);
32944
+ replyTarget = messageId;
32929
32945
  emit2();
32930
32946
  },
32931
32947
  closeThread() {
32932
- if (openThreadRootId === null) return;
32948
+ if (openThreadRootId === null && replyTarget === null) return;
32933
32949
  openThreadRootId = null;
32950
+ replyTarget = null;
32934
32951
  emit2();
32935
32952
  },
32936
32953
  setThreadingMode(mode) {
@@ -33274,6 +33291,7 @@ function useConversation(config) {
33274
33291
  retryLast: api.retryLast,
33275
33292
  stop: api.stop,
33276
33293
  openThread: api.openThread,
33294
+ replyTo: api.replyTo,
33277
33295
  closeThread: api.closeThread,
33278
33296
  setThreadingMode: api.setThreadingMode
33279
33297
  };
@@ -33736,7 +33754,7 @@ function HoverActions({
33736
33754
  onToggleEmojis,
33737
33755
  align
33738
33756
  }) {
33739
- const { state, openThread, deleteMessage } = conversation;
33757
+ const { replyTo, deleteMessage } = conversation;
33740
33758
  return h2(
33741
33759
  "div",
33742
33760
  {
@@ -33745,7 +33763,8 @@ function HoverActions({
33745
33763
  align === "end" && "justify-end"
33746
33764
  )
33747
33765
  },
33748
- h2("button", { type: "button", className: "hover:text-foreground", onClick: () => openThread(rootIdOf(state.messages, message.id)) }, "Reply"),
33766
+ // Reply targets this specific message but groups under the originating root.
33767
+ h2("button", { type: "button", className: "hover:text-foreground", onClick: () => replyTo(message.id) }, "Reply"),
33749
33768
  h2("button", { type: "button", className: "hover:text-foreground", onClick: onToggleEmojis }, "React"),
33750
33769
  isOwn ? h2("button", { type: "button", className: "hover:text-foreground", onClick: onEdit }, "Edit") : null,
33751
33770
  isOwn ? h2("button", { type: "button", className: "hover:text-destructive", onClick: () => deleteMessage(message.id) }, "Delete") : null
@@ -33807,7 +33826,7 @@ function MessageRow({
33807
33826
  const inner = h2(
33808
33827
  React11__namespace.Fragment,
33809
33828
  null,
33810
- quotedParent ? h2(QuotedParent, { parent: quotedParent, onClick: () => openThread(quotedParent.id) }) : null,
33829
+ quotedParent ? h2(QuotedParent, { parent: quotedParent, onClick: () => openThread(rootIdOf(state.messages, quotedParent.id)) }) : null,
33811
33830
  editing ? h2(EditField, { message, conversation, onDone: () => setEditing(false) }) : isUser ? h2("div", { className: "inline-block rounded-2xl rounded-br-sm bg-primary/10 px-3 py-2 text-left" }, h2(MessageBody, { message })) : h2(MessageBody, { message }),
33812
33831
  h2(Reactions, { message, onReact: (e2) => react(message.id, e2), align }),
33813
33832
  showThreadAffordance && replyCount > 0 ? h2(
@@ -33907,13 +33926,14 @@ function ThreadPanel({ conversation, currentUserId, composer }) {
33907
33926
  const rootId = state.openThreadRootId;
33908
33927
  if (!rootId) return null;
33909
33928
  const messages = selectThreadMessages(state.messages, rootId);
33929
+ const target = state.replyTarget && state.replyTarget !== rootId ? findMessage(state.messages, state.replyTarget) : void 0;
33910
33930
  return h2(
33911
33931
  "aside",
33912
33932
  { className: "flex w-80 flex-col border-l border-border", "aria-label": "Thread" },
33913
33933
  h2(
33914
33934
  "div",
33915
33935
  { className: "flex items-center justify-between border-b border-border px-3 py-2" },
33916
- h2("span", { className: "text-sm font-semibold" }, "Thread"),
33936
+ h2("span", { className: "text-sm font-semibold" }, `Thread \xB7 ${messages.length - 1} ${messages.length - 1 === 1 ? "reply" : "replies"}`),
33917
33937
  h2("button", { type: "button", className: "text-muted-foreground hover:text-foreground", "aria-label": "Close thread", onClick: () => conversation.closeThread() }, "\u2715")
33918
33938
  ),
33919
33939
  h2(
@@ -33921,6 +33941,12 @@ function ThreadPanel({ conversation, currentUserId, composer }) {
33921
33941
  { className: "flex-1 overflow-y-auto p-1" },
33922
33942
  ...messages.map((m2) => h2(MessageRow, { key: m2.id, message: m2, conversation, currentUserId, showThreadAffordance: false }))
33923
33943
  ),
33944
+ target ? h2(
33945
+ "div",
33946
+ { className: "flex items-center justify-between gap-2 border-t border-border bg-muted/40 px-3 py-1 text-xs text-muted-foreground" },
33947
+ h2("span", { className: "truncate" }, `\u21B3 Replying to ${target.author.name}`),
33948
+ h2("button", { type: "button", className: "hover:text-foreground", onClick: () => conversation.openThread(rootId) }, "Reply to thread instead")
33949
+ ) : null,
33924
33950
  composer
33925
33951
  );
33926
33952
  }
@@ -33976,7 +34002,7 @@ function Chat({
33976
34002
  mentions,
33977
34003
  onSlashCommand,
33978
34004
  toolbar: composerToolbar,
33979
- onSubmit: (content, atts) => void sendMessage(content, { replyTo: state.openThreadRootId, attachments: atts }),
34005
+ onSubmit: (content, atts) => void sendMessage(content, { replyTo: state.replyTarget ?? state.openThreadRootId, attachments: atts }),
33980
34006
  onStop: () => conversation.stop()
33981
34007
  }) : null;
33982
34008
  const body = timeline.length === 0 ? h2("div", { className: "flex flex-1 items-center justify-center p-6 text-sm text-muted-foreground" }, emptyState ?? "No messages yet. Say hello \u{1F44B}") : h2(
@@ -33988,8 +34014,10 @@ function Chat({
33988
34014
  message: m2,
33989
34015
  conversation,
33990
34016
  currentUserId,
33991
- showThreadAffordance: state.threadingMode === "panel",
33992
- quotedParent: state.threadingMode === "inline" && m2.parentId ? findMessage(state.messages, m2.parentId) : void 0
34017
+ // Show the "N replies" count on originating messages in BOTH modes.
34018
+ showThreadAffordance: true,
34019
+ // Inline: quote the specific message replied to (falls back to the root).
34020
+ quotedParent: state.threadingMode === "inline" && m2.parentId ? findMessage(state.messages, m2.replyToId ?? m2.parentId) : void 0
33993
34021
  })
33994
34022
  )
33995
34023
  );