@tangle-network/ui 11.51.12 → 11.51.13

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/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 11.51.13
2
+
3
+ ### Patch Changes
4
+
5
+ - 919beef: The user's turn in `UserMessage` and `ChatMessage` is an indigo tint (`bg-primary/15`, foreground text) instead of the inverted foreground bubble, which rendered near-white in dark mode beside dark transcripts (run-page panel, 2026-11-04).
6
+
1
7
  ## 11.51.12
2
8
 
3
9
  ### Patch Changes
@@ -32,7 +32,7 @@ function ChatMessage({ role, content, toolCalls, isStreaming, timestamp, classNa
32
32
  children: formatUtcTime(timestamp)
33
33
  })]
34
34
  }), /* @__PURE__ */ jsxs("div", {
35
- className: cn("min-w-0 max-w-[85%] space-y-1", fromViewer ? "rounded-[var(--radius-lg)] bg-foreground px-[var(--chat-message-px)] py-[var(--chat-message-py)] text-background" : fromOtherPerson ? "rounded-[var(--radius-lg)] border border-border bg-card px-[var(--chat-message-px)] py-[var(--chat-message-py)] text-foreground" : isAssistant ? "text-foreground" : "rounded-[var(--radius-lg)] border border-border bg-card px-[var(--chat-message-px)] py-[var(--chat-message-py)]"),
35
+ className: cn("min-w-0 max-w-[85%] space-y-1", fromViewer ? "rounded-[var(--radius-lg)] bg-primary/15 px-[var(--chat-message-px)] py-[var(--chat-message-py)] text-foreground" : fromOtherPerson ? "rounded-[var(--radius-lg)] border border-border bg-card px-[var(--chat-message-px)] py-[var(--chat-message-py)] text-foreground" : isAssistant ? "text-foreground" : "rounded-[var(--radius-lg)] border border-border bg-card px-[var(--chat-message-px)] py-[var(--chat-message-py)]"),
36
36
  children: [isUser ? /* @__PURE__ */ jsx("div", {
37
37
  className: cn("whitespace-pre-wrap", TRANSCRIPT_TEXT),
38
38
  children: content
@@ -61,7 +61,7 @@ function UserBubble({ text, timestamp, actions, lines }) {
61
61
  children: /* @__PURE__ */ jsxs("div", {
62
62
  className: "group flex min-w-0 max-w-[78%] flex-col items-end gap-2",
63
63
  children: [/* @__PURE__ */ jsxs("div", {
64
- className: "relative w-full min-w-0 rounded-2xl bg-foreground px-4 py-3 text-background",
64
+ className: "relative w-full min-w-0 rounded-2xl bg-primary/15 px-4 py-3 text-foreground",
65
65
  children: [timestamp ? /* @__PURE__ */ jsx("span", {
66
66
  "data-user-message-time": "",
67
67
  className: "pointer-events-none absolute right-full top-1/2 mr-3 -translate-y-1/2 whitespace-nowrap text-sm text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/ui",
3
- "version": "11.51.12",
3
+ "version": "11.51.13",
4
4
  "description": "Generic React UI components for Tangle products — primitives, chat, run, files, editor, markdown.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -95,7 +95,7 @@ export function ChatMessage({
95
95
  className={cn(
96
96
  "min-w-0 max-w-[85%] space-y-1",
97
97
  fromViewer
98
- ? "rounded-[var(--radius-lg)] bg-foreground px-[var(--chat-message-px)] py-[var(--chat-message-py)] text-background"
98
+ ? "rounded-[var(--radius-lg)] bg-primary/15 px-[var(--chat-message-px)] py-[var(--chat-message-py)] text-foreground"
99
99
  : fromOtherPerson
100
100
  ? "rounded-[var(--radius-lg)] border border-border bg-card px-[var(--chat-message-px)] py-[var(--chat-message-py)] text-foreground"
101
101
  : isAssistant
@@ -23,12 +23,12 @@ const segmentedParts: SessionPart[] = [
23
23
  describe("a transcript without authors", () => {
24
24
 
25
25
  it("renders UserMessage actions and application notes as before", () => {
26
- expect(html(<UserMessage content="Can I break my lease early?" actions={<button type="button">Copy</button>} />)).toMatchInlineSnapshot(`"<div class="flex justify-end"><div class="group flex min-w-0 max-w-[78%] flex-col items-end gap-2"><div class="relative w-full min-w-0 rounded-2xl bg-foreground px-4 py-3 text-background"><div class="break-words whitespace-pre-wrap tangle-transcript-text text-[length:var(--transcript-font-size)] leading-[var(--transcript-line-height)]">Can I break my lease early?</div></div><div class="flex flex-wrap items-center justify-end gap-1.5 text-sm text-muted-foreground"><button type="button">Copy</button></div></div></div>"`)
27
- expect(html(<UserMessage parts={segmentedParts} actions={<button type="button">Copy</button>} />)).toMatchInlineSnapshot(`"<div class="space-y-2"><div class="flex justify-end"><div class="group flex min-w-0 max-w-[78%] flex-col items-end gap-2"><div class="relative w-full min-w-0 rounded-2xl bg-foreground px-4 py-3 text-background"><div class="break-words whitespace-pre-wrap tangle-transcript-text text-[length:var(--transcript-font-size)] leading-[var(--transcript-line-height)]">I signed the lease in March.</div></div></div></div><div role="note" aria-label="Application note" data-synthetic-text="" class="min-w-0 rounded-md border border-dashed border-border bg-muted/30 px-3 py-2 text-sm text-muted-foreground"><div class="mb-1 font-medium">Application note</div><div class="break-words whitespace-pre-wrap">Lease uploaded: lease.pdf</div></div><div class="flex justify-end"><div class="group flex min-w-0 max-w-[78%] flex-col items-end gap-2"><div class="relative w-full min-w-0 rounded-2xl bg-foreground px-4 py-3 text-background"><div class="break-words whitespace-pre-wrap tangle-transcript-text text-[length:var(--transcript-font-size)] leading-[var(--transcript-line-height)]">Here it is.</div></div></div></div><div class="flex flex-wrap items-center justify-end gap-1.5 text-sm text-muted-foreground"><button type="button">Copy</button></div></div>"`)
26
+ expect(html(<UserMessage content="Can I break my lease early?" actions={<button type="button">Copy</button>} />)).toMatchInlineSnapshot(`"<div class="flex justify-end"><div class="group flex min-w-0 max-w-[78%] flex-col items-end gap-2"><div class="relative w-full min-w-0 rounded-2xl bg-primary/15 px-4 py-3 text-foreground"><div class="break-words whitespace-pre-wrap tangle-transcript-text text-[length:var(--transcript-font-size)] leading-[var(--transcript-line-height)]">Can I break my lease early?</div></div><div class="flex flex-wrap items-center justify-end gap-1.5 text-sm text-muted-foreground"><button type="button">Copy</button></div></div></div>"`)
27
+ expect(html(<UserMessage parts={segmentedParts} actions={<button type="button">Copy</button>} />)).toMatchInlineSnapshot(`"<div class="space-y-2"><div class="flex justify-end"><div class="group flex min-w-0 max-w-[78%] flex-col items-end gap-2"><div class="relative w-full min-w-0 rounded-2xl bg-primary/15 px-4 py-3 text-foreground"><div class="break-words whitespace-pre-wrap tangle-transcript-text text-[length:var(--transcript-font-size)] leading-[var(--transcript-line-height)]">I signed the lease in March.</div></div></div></div><div role="note" aria-label="Application note" data-synthetic-text="" class="min-w-0 rounded-md border border-dashed border-border bg-muted/30 px-3 py-2 text-sm text-muted-foreground"><div class="mb-1 font-medium">Application note</div><div class="break-words whitespace-pre-wrap">Lease uploaded: lease.pdf</div></div><div class="flex justify-end"><div class="group flex min-w-0 max-w-[78%] flex-col items-end gap-2"><div class="relative w-full min-w-0 rounded-2xl bg-primary/15 px-4 py-3 text-foreground"><div class="break-words whitespace-pre-wrap tangle-transcript-text text-[length:var(--transcript-font-size)] leading-[var(--transcript-line-height)]">Here it is.</div></div></div></div><div class="flex flex-wrap items-center justify-end gap-1.5 text-sm text-muted-foreground"><button type="button">Copy</button></div></div>"`)
28
28
  })
29
29
 
30
30
  it("renders UserMessage as before", () => {
31
- expect(html(<UserMessage content="Can I break my lease early?" />)).toMatchInlineSnapshot(`"<div class="flex justify-end"><div class="group flex min-w-0 max-w-[78%] flex-col items-end gap-2"><div class="relative w-full min-w-0 rounded-2xl bg-foreground px-4 py-3 text-background"><div class="break-words whitespace-pre-wrap tangle-transcript-text text-[length:var(--transcript-font-size)] leading-[var(--transcript-line-height)]">Can I break my lease early?</div></div></div></div>"`)
31
+ expect(html(<UserMessage content="Can I break my lease early?" />)).toMatchInlineSnapshot(`"<div class="flex justify-end"><div class="group flex min-w-0 max-w-[78%] flex-col items-end gap-2"><div class="relative w-full min-w-0 rounded-2xl bg-primary/15 px-4 py-3 text-foreground"><div class="break-words whitespace-pre-wrap tangle-transcript-text text-[length:var(--transcript-font-size)] leading-[var(--transcript-line-height)]">Can I break my lease early?</div></div></div></div>"`)
32
32
  })
33
33
 
34
34
  })
@@ -92,7 +92,7 @@ describe("UserMessage with an author", () => {
92
92
  const { container } = render(<UserMessage content="Did you give a forwarding address?" author={attorney} viewerId={client.id} />)
93
93
  expect(container.firstElementChild?.className).toContain("justify-start")
94
94
  expect(bubbleOf("Did you give a forwarding address?").className).toContain("bg-card")
95
- expect(bubbleOf("Did you give a forwarding address?").className).not.toContain("bg-foreground")
95
+ expect(bubbleOf("Did you give a forwarding address?").className).not.toContain("bg-primary/15")
96
96
  expect(screen.getByText("Jane Doe")).toBeInTheDocument()
97
97
  expect(screen.getByText("Attorney")).toBeInTheDocument()
98
98
  })
@@ -148,7 +148,7 @@ describe("AgentTimeline with three participants", () => {
148
148
 
149
149
  it("sets the client's own words apart from the attorney's on the client's screen", () => {
150
150
  render(<AgentTimeline items={thread} viewerId={client.id} />)
151
- expect(bubbleOf("My landlord kept my deposit.").className).toContain("bg-foreground")
151
+ expect(bubbleOf("My landlord kept my deposit.").className).toContain("bg-primary/15")
152
152
  expect(screen.queryByText("Maria Lopez")).not.toBeInTheDocument()
153
153
  expect(bubbleOf("Did you give a forwarding address?").className).toContain("bg-card")
154
154
  expect(screen.getByText("Jane Doe")).toBeInTheDocument()
@@ -156,7 +156,7 @@ describe("AgentTimeline with three participants", () => {
156
156
 
157
157
  it("mirrors the thread on the attorney's screen", () => {
158
158
  render(<AgentTimeline items={thread} viewerId={attorney.id} />)
159
- expect(bubbleOf("Did you give a forwarding address?").className).toContain("bg-foreground")
159
+ expect(bubbleOf("Did you give a forwarding address?").className).toContain("bg-primary/15")
160
160
  expect(bubbleOf("My landlord kept my deposit.").className).toContain("bg-card")
161
161
  expect(screen.getByText("Maria Lopez")).toBeInTheDocument()
162
162
  expect(screen.queryByText("Jane Doe")).not.toBeInTheDocument()
@@ -12,7 +12,7 @@ type Part =
12
12
  function Turn({ parts, live = false }: { parts: Part[]; live?: boolean }) {
13
13
  return (
14
14
  <div className="mx-auto flex w-full max-w-3xl flex-col gap-6 px-4 py-6">
15
- <p className={`ml-auto w-fit max-w-[78%] rounded-2xl bg-foreground px-4 py-3 text-background ${TRANSCRIPT_TEXT}`}>
15
+ <p className={`ml-auto w-fit max-w-[78%] rounded-2xl bg-primary/15 px-4 py-3 text-foreground ${TRANSCRIPT_TEXT}`}>
16
16
  @writer @research-lead plan the launch announcement for the roster feature.
17
17
  </p>
18
18
  {partitionBySpeaker(parts).map(({ speaker, parts: own }) => (
@@ -38,7 +38,7 @@ describe("user text boundaries", () => {
38
38
 
39
39
  it("preserves a single joined bubble when no application note is present", () => {
40
40
  const { container } = render(<UserMessage parts={mixed.slice(0, 2)} />);
41
- expect(container.querySelectorAll(".bg-foreground.text-background")).toHaveLength(1);
41
+ expect(container.querySelectorAll(".bg-primary\\/15")).toHaveLength(1);
42
42
  expect(container.querySelector(".whitespace-pre-wrap")?.textContent).toBe("First\nSecond");
43
43
  expect(screen.queryByRole("note")).not.toBeInTheDocument();
44
44
  });
@@ -61,7 +61,7 @@ describe("user text boundaries", () => {
61
61
  const { container } = render(<UserMessage parts={[mixed[2]]} actions={<button type="button">Inspect receipt</button>} />);
62
62
  expect(screen.getByRole("note")).toHaveTextContent("Receipt");
63
63
  expect(screen.getByRole("button", { name: "Inspect receipt" })).toBeInTheDocument();
64
- expect(container.querySelector(".bg-foreground")).toBeNull();
64
+ expect(container.querySelector(".bg-primary\\/15")).toBeNull();
65
65
  });
66
66
 
67
67
  it("retains direct-content timestamps", () => {
@@ -96,7 +96,7 @@ function UserBubble({ text, timestamp, actions, lines }: {
96
96
  return (
97
97
  <div className="flex justify-end">
98
98
  <div className="group flex min-w-0 max-w-[78%] flex-col items-end gap-2">
99
- <div className="relative w-full min-w-0 rounded-2xl bg-foreground px-4 py-3 text-background">
99
+ <div className="relative w-full min-w-0 rounded-2xl bg-primary/15 px-4 py-3 text-foreground">
100
100
  {timestamp ? (
101
101
  <span
102
102
  data-user-message-time=""