From 0c8eaaf74bbac02c022616aff74b730d9b05c0fc Mon Sep 17 00:00:00 2001 From: maaz519 Date: Sat, 25 Jul 2026 17:01:55 +0530 Subject: [PATCH] fix(messaging-ui): unreadable code chip on own messages + raw markers in previews MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two bugs from the formatting work, both visible in the CRM messenger: 1. Inline code / code blocks were invisible in your OWN bubbles. `.miu-code` sets background: --miu-panel-2 (#1d1d26) while the is-mine override set only the colour to --miu-accent-text (#1a1206) — near-black on near-black, ~1.03:1 contrast. The chip now tints the accent bubble (rgba(0,0,0,.16)) instead of using the panel colour, so it reads against any accent. 2. The conversation list showed the raw last message, so a strikethrough message previewed as "~crazy~". Adds stripMarkup() — markers off, code unwrapped, nesting handled, honouring the same word-boundary rule so snake_case_name and "5 * 3" survive — and uses it for the preview line. Bumped to 0.1.10. SDK suite: 17 files / 98 tests green. Co-Authored-By: Claude Opus 4.8 --- packages/iios-messaging-ui/package.json | 2 +- .../src/components/conversation-list.tsx | 3 ++- packages/iios-messaging-ui/src/index.ts | 2 +- .../iios-messaging-ui/src/rich-text.test.tsx | 20 ++++++++++++++++++- packages/iios-messaging-ui/src/rich-text.tsx | 19 ++++++++++++++++++ packages/iios-messaging-ui/src/styles.css | 10 ++++++++-- 6 files changed, 50 insertions(+), 6 deletions(-) diff --git a/packages/iios-messaging-ui/package.json b/packages/iios-messaging-ui/package.json index 78d31d1..9f968ac 100644 --- a/packages/iios-messaging-ui/package.json +++ b/packages/iios-messaging-ui/package.json @@ -1,6 +1,6 @@ { "name": "@insignia/iios-messaging-ui", - "version": "0.1.9", + "version": "0.1.10", "type": "module", "main": "dist/index.js", "module": "dist/index.js", diff --git a/packages/iios-messaging-ui/src/components/conversation-list.tsx b/packages/iios-messaging-ui/src/components/conversation-list.tsx index 828a910..f4ba1c3 100644 --- a/packages/iios-messaging-ui/src/components/conversation-list.tsx +++ b/packages/iios-messaging-ui/src/components/conversation-list.tsx @@ -1,4 +1,5 @@ import type { Conversation } from '../types'; +import { stripMarkup } from '../rich-text'; /** Initials for the avatar chip — first letters of the first two words. */ function initials(title: string): string { @@ -37,7 +38,7 @@ export function ConversationList({ {c.title} - {c.lastMessage ? {c.lastMessage} : null} + {c.lastMessage ? {stripMarkup(c.lastMessage)} : null} {c.unread > 0 ? ( diff --git a/packages/iios-messaging-ui/src/index.ts b/packages/iios-messaging-ui/src/index.ts index 466ef9e..1275866 100644 --- a/packages/iios-messaging-ui/src/index.ts +++ b/packages/iios-messaging-ui/src/index.ts @@ -10,7 +10,7 @@ export { useChannels } from './hooks/use-channels'; export { useMembers } from './hooks/use-members'; export { isOwnMessage } from './types'; // Message-body markup (bold/italic/strike/code/links + mentions) as a safe ReactNode tree. -export { renderRichText, safeHref } from './rich-text'; +export { renderRichText, safeHref, stripMarkup } from './rich-text'; // Rendered UI. Pair with the './styles.css' export (or override the --miu-* tokens). export { Messenger } from './components/messenger'; diff --git a/packages/iios-messaging-ui/src/rich-text.test.tsx b/packages/iios-messaging-ui/src/rich-text.test.tsx index 46d3802..6fb6691 100644 --- a/packages/iios-messaging-ui/src/rich-text.test.tsx +++ b/packages/iios-messaging-ui/src/rich-text.test.tsx @@ -1,6 +1,6 @@ import { describe, it, expect } from 'vitest'; import { render, screen } from '@testing-library/react'; -import { renderRichText, safeHref } from './rich-text'; +import { renderRichText, safeHref, stripMarkup } from './rich-text'; function show(text: string, names: string[] = []) { render(
{renderRichText(text, names)}
); @@ -75,3 +75,21 @@ describe('renderRichText', () => { expect(show('just a normal message').textContent).toBe('just a normal message'); }); }); + +describe('stripMarkup (one-line previews)', () => { + it('drops the markers so a preview never shows ~crazy~', () => { + expect(stripMarkup('~crazy~')).toBe('crazy'); + expect(stripMarkup('*bold* and _italic_')).toBe('bold and italic'); + }); + + it('unwraps code and flattens a fenced block', () => { + expect(stripMarkup('run `npm ci` now')).toBe('run npm ci now'); + expect(stripMarkup('```\nconst a = 1;\n```')).toBe('const a = 1;'); + }); + + it('handles nesting and leaves ordinary text (and identifiers) alone', () => { + expect(stripMarkup('*bold with _italic_*')).toBe('bold with italic'); + expect(stripMarkup('snake_case_name and 5 * 3')).toBe('snake_case_name and 5 * 3'); + expect(stripMarkup('plain preview')).toBe('plain preview'); + }); +}); diff --git a/packages/iios-messaging-ui/src/rich-text.tsx b/packages/iios-messaging-ui/src/rich-text.tsx index f0a94bd..b760f21 100644 --- a/packages/iios-messaging-ui/src/rich-text.tsx +++ b/packages/iios-messaging-ui/src/rich-text.tsx @@ -71,6 +71,25 @@ function firstSpan(text: string): { start: number; end: number; rule: Rule; inne return best; } +/** + * The same text with its formatting markers removed, for places that show a one-line plain-text + * preview (conversation list, notifications) where `~crazy~` must read as "crazy" — you cannot + * render nodes into those, so the markers have to come off rather than be styled. + */ +export function stripMarkup(text: string): string { + const noCode = text + .replace(/```([\s\S]*?)```/g, (_m, code: string) => code.trim()) + .replace(/`([^`\n]+)`/g, '$1'); + return stripSpans(noCode); +} + +/** Recursively drop *bold* / _italic_ / ~strike~ markers, honouring the same word-boundary rule. */ +function stripSpans(text: string): string { + const span = firstSpan(text); + if (!span) return text; + return text.slice(0, span.start) + stripSpans(span.inner) + stripSpans(text.slice(span.end)); +} + /** Linkify + mention-highlight a run of text that carries no other markup. */ function plain(text: string, memberNames: string[], keyed: () => string): ReactNode[] { const out: ReactNode[] = []; diff --git a/packages/iios-messaging-ui/src/styles.css b/packages/iios-messaging-ui/src/styles.css index 2c8922e..0340cf0 100644 --- a/packages/iios-messaging-ui/src/styles.css +++ b/packages/iios-messaging-ui/src/styles.css @@ -568,8 +568,14 @@ button.miu-attach-dl:hover { color: var(--miu-accent); text-decoration: underline; } -.miu-msg.is-mine .miu-bubble .miu-link, -.miu-msg.is-mine .miu-bubble .miu-code { +.miu-msg.is-mine .miu-bubble .miu-link { + color: var(--miu-accent-text); +} +/* On your own (accent-filled) bubble the panel background would sit dark-on-dark against the dark + accent text — tint the bubble instead so the chip reads on any accent colour. */ +.miu-msg.is-mine .miu-bubble .miu-code, +.miu-msg.is-mine .miu-bubble .miu-code-block { + background: rgba(0, 0, 0, 0.16); color: var(--miu-accent-text); } .miu-send {