Conversation
📝 WalkthroughWalkthroughReplaces many inline/Tailwind-like classes with BEM-style CSS, restructures BlockKit container and per-block wrappers, adds emoji rendering support (renderEmoji with large option and richer c-emoji markup/ARIA), updates rich-text/list sanitisation and markup, and removes the WorkspaceSelect onChange prop and its call sites. Changes
Sequence Diagram(s)sequenceDiagram
participant RichText as RichTextBlock
participant Context as BlockKitContext
participant MRKDWN as packages/mrkdwn
participant DOM as Browser DOM
RichText->>Context: renderText / detect :name:
Context->>MRKDWN: resolveEmoji(name)
MRKDWN-->>Context: emoji metadata or unicode
Context->>MRKDWN: renderEmoji(name, { large? })
MRKDWN-->>Context: HTML (c-emoji + tooltip + attrs)
Context->>RichText: return rendered HTML fragment
RichText->>DOM: insert HTML (c-emoji, lists, pre, quote)
DOM-->>RichText: hover shows c-emoji__tooltip (CSS-controlled)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte (1)
4-9: Use$libalias for imports fromsrc/lib/.As per coding guidelines, imports from
src/lib/should use the$libpath alias.♻️ Suggested fix
- import type { - RichTextBlockElement, - RichTextInlineElement, - RichTextStyle, - SlackRichTextBlock, - } from '../../../lib/types' + import type { + RichTextBlockElement, + RichTextInlineElement, + RichTextStyle, + SlackRichTextBlock, + } from '$lib/types'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte` around lines 4 - 9, Update the import path in RichTextBlock.svelte to use the $lib alias: replace the relative import '../../../lib/types' that brings in RichTextBlockElement, RichTextInlineElement, RichTextStyle, and SlackRichTextBlock with an alias import from '$lib/types' so the types are imported via the project path alias.apps/ui/src/components/blockkit/BlockKitRenderer.svelte (1)
15-16: Use$libalias for imports fromsrc/lib/.As per coding guidelines, imports from
src/lib/should use the$libpath alias.♻️ Suggested fix
- import type { - SlackBlock, - SlackSectionBlock, - SlackInputBlock, - SlackActionsBlock, - SlackContextBlock, - SlackContextActionsBlock, - SlackImageBlock, - SlackHeaderBlock, - SlackRichTextBlock, - SlackTableBlock, - SlackOption, - UploadedFile, - } from '../../lib/types' + import type { + SlackBlock, + SlackSectionBlock, + SlackInputBlock, + SlackActionsBlock, + SlackContextBlock, + SlackContextActionsBlock, + SlackImageBlock, + SlackHeaderBlock, + SlackRichTextBlock, + SlackTableBlock, + SlackOption, + UploadedFile, + } from '$lib/types'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/ui/src/components/blockkit/BlockKitRenderer.svelte` around lines 15 - 16, Change the relative import from src/lib to use the $lib alias: replace the import that currently reads from '../../lib/types' with an import from '$lib/types' (leave local imports like './context' unchanged); update any other imports in BlockKitRenderer.svelte that reference src/lib to use the $lib alias so the TypeScript types (e.g., the imported types) resolve via the path alias.apps/ui/src/components/blockkit/elements/StaticSelect.svelte (1)
2-6: Use$libalias for imports fromsrc/lib/.As per coding guidelines, imports from
src/lib/should use the$libpath alias.♻️ Suggested fix
- import type { - SlackStaticSelectElement, - SlackOption, - } from '../../../lib/types' + import type { + SlackStaticSelectElement, + SlackOption, + } from '$lib/types'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/ui/src/components/blockkit/elements/StaticSelect.svelte` around lines 2 - 6, Replace the relative import of types with the $lib alias: change the import of SlackStaticSelectElement and SlackOption from '../../../lib/types' to '$lib/types' while keeping the renderText import as-is; update the import statement that references SlackStaticSelectElement and SlackOption so it uses the $lib path alias.packages/mrkdwn/src/emoji.ts (1)
34-35: Consider BEM modifier naming convention.The class
c-emoji__largeuses double underscore (__), which in BEM convention denotes an element of a block. Since "large" is a size modifier of the emoji block, the BEM convention would bec-emoji--large(double hyphen).This is a minor naming consistency suggestion; if the current naming is intentional for alignment with Slack's own CSS conventions, feel free to disregard.
♻️ BEM-compliant naming
- const cls = options?.large ? 'c-emoji c-emoji__large' : 'c-emoji' + const cls = options?.large ? 'c-emoji c-emoji--large' : 'c-emoji'Note: This would also require updating the corresponding CSS selectors in
RichTextBlock.svelteand any other stylesheets.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mrkdwn/src/emoji.ts` around lines 34 - 35, The BEM naming for the large modifier is incorrect: change the class construction in the cls assignment (which currently uses c-emoji__large) to use the modifier convention c-emoji--large when options?.large is true, and update any usages and styles that reference c-emoji__large (e.g., selectors in RichTextBlock.svelte and related stylesheets) to the new c-emoji--large to keep markup and CSS consistent with BEM.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
apps/ui/src/app.cssapps/ui/src/components/blockkit/BlockKitRenderer.svelteapps/ui/src/components/blockkit/blocks/ActionsBlock.svelteapps/ui/src/components/blockkit/blocks/ContextActionsBlock.svelteapps/ui/src/components/blockkit/blocks/HeaderBlock.svelteapps/ui/src/components/blockkit/blocks/RichTextBlock.svelteapps/ui/src/components/blockkit/context.tsapps/ui/src/components/blockkit/elements/Button.svelteapps/ui/src/components/blockkit/elements/StaticSelect.svelteapps/ui/src/components/blockkit/elements/WorkspaceSelect.sveltebunfig.tomlpackages/mrkdwn/src/emoji.tspackages/mrkdwn/src/index.tspackages/mrkdwn/src/mrkdwn-to-html.test.ts
💤 Files with no reviewable changes (1)
- bunfig.toml
🧰 Additional context used
📓 Path-based instructions (5)
**/*.svelte
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.svelte: Use{@html}in Svelte for mrkdwn rendering (ESLint rule disabled for this specific use case)
Use Svelte 5 runes ($state,$derived,$effect) for reactivity instead of legacy stores
Files:
apps/ui/src/components/blockkit/elements/Button.svelteapps/ui/src/components/blockkit/elements/WorkspaceSelect.svelteapps/ui/src/components/blockkit/blocks/HeaderBlock.svelteapps/ui/src/components/blockkit/blocks/RichTextBlock.svelteapps/ui/src/components/blockkit/BlockKitRenderer.svelteapps/ui/src/components/blockkit/blocks/ContextActionsBlock.svelteapps/ui/src/components/blockkit/blocks/ActionsBlock.svelteapps/ui/src/components/blockkit/elements/StaticSelect.svelte
apps/ui/src/**/*.{ts,tsx,svelte}
📄 CodeRabbit inference engine (CLAUDE.md)
Use
$libpath alias when importing fromsrc/lib/in Svelte applications
Files:
apps/ui/src/components/blockkit/elements/Button.svelteapps/ui/src/components/blockkit/elements/WorkspaceSelect.svelteapps/ui/src/components/blockkit/blocks/HeaderBlock.svelteapps/ui/src/components/blockkit/context.tsapps/ui/src/components/blockkit/blocks/RichTextBlock.svelteapps/ui/src/components/blockkit/BlockKitRenderer.svelteapps/ui/src/components/blockkit/blocks/ContextActionsBlock.svelteapps/ui/src/components/blockkit/blocks/ActionsBlock.svelteapps/ui/src/components/blockkit/elements/StaticSelect.svelte
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js,jsx}: Use camelCase for variable names in TypeScript/JavaScript code
No semicolons in code, enforced by Prettier
Use single quotes instead of double quotes
Use trailing commas in es5 format
Prefix unused variables with underscore (_)
Files:
packages/mrkdwn/src/emoji.tspackages/mrkdwn/src/index.tsapps/ui/src/components/blockkit/context.tspackages/mrkdwn/src/mrkdwn-to-html.test.ts
packages/mrkdwn/src/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Slack mrkdwn converter must provide bidirectional conversion (mrkdwn to HTML and Markdown to mrkdwn)
Files:
packages/mrkdwn/src/emoji.tspackages/mrkdwn/src/index.tspackages/mrkdwn/src/mrkdwn-to-html.test.ts
**/*.test.ts
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.test.ts: Test files should be colocated with source code using*.test.tsnaming convention
Use Bun's built-in test runner (bun:test) for all tests
Files:
packages/mrkdwn/src/mrkdwn-to-html.test.ts
🧠 Learnings (3)
📚 Learning: 2026-01-14T21:36:07.933Z
Learnt from: tyom
Repo: tyom/botarium PR: 1
File: apps/ui/src/components/MessagePanel.svelte:10-23
Timestamp: 2026-01-14T21:36:07.933Z
Learning: In the client-only Botarium UI (Vite + Svelte), do not add or rely on SSR-specific guards (e.g., checks for sessionStorage) in components. Since the app runs only in Electron or the browser, code that accesses browser APIs will execute in a non-SSR environment, so SSR-unsafe checks are unnecessary and can be removed for maintainability.
Applied to files:
apps/ui/src/components/blockkit/elements/Button.svelteapps/ui/src/components/blockkit/elements/WorkspaceSelect.svelteapps/ui/src/components/blockkit/blocks/HeaderBlock.svelteapps/ui/src/components/blockkit/blocks/RichTextBlock.svelteapps/ui/src/components/blockkit/BlockKitRenderer.svelteapps/ui/src/components/blockkit/blocks/ContextActionsBlock.svelteapps/ui/src/components/blockkit/blocks/ActionsBlock.svelteapps/ui/src/components/blockkit/elements/StaticSelect.svelte
📚 Learning: 2026-02-20T00:31:35.696Z
Learnt from: CR
Repo: tyom/botarium PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-20T00:31:35.696Z
Learning: Applies to packages/mrkdwn/src/**/*.ts : Slack mrkdwn converter must provide bidirectional conversion (mrkdwn to HTML and Markdown to mrkdwn)
Applied to files:
packages/mrkdwn/src/emoji.tspackages/mrkdwn/src/index.tsapps/ui/src/components/blockkit/context.tspackages/mrkdwn/src/mrkdwn-to-html.test.tsapps/ui/src/components/blockkit/blocks/RichTextBlock.svelte
📚 Learning: 2026-02-20T00:31:35.696Z
Learnt from: CR
Repo: tyom/botarium PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-20T00:31:35.696Z
Learning: Applies to **/*.svelte : Use `{html}` in Svelte for mrkdwn rendering (ESLint rule disabled for this specific use case)
Applied to files:
packages/mrkdwn/src/index.tsapps/ui/src/components/blockkit/context.tspackages/mrkdwn/src/mrkdwn-to-html.test.tsapps/ui/src/components/blockkit/blocks/RichTextBlock.svelte
🧬 Code graph analysis (1)
packages/mrkdwn/src/emoji.ts (1)
packages/mrkdwn/src/index.ts (2)
renderEmoji(3-3)resolveEmoji(3-3)
🔇 Additional comments (16)
apps/ui/src/components/blockkit/blocks/ActionsBlock.svelte (1)
32-115: Nice structural clean-up for action layout.The wrapper structure and scoped flex styles are tidy and should preserve behaviour while standardising layout.
apps/ui/src/components/blockkit/blocks/ContextActionsBlock.svelte (1)
21-66: Wrapper class swap and scoped styles look good.Keeps the layout semantics clear without affecting behaviour.
apps/ui/src/app.css (1)
395-447: Emoji selector migration is consistent with the new naming.The tooltip styling updates look coherent with the new c-emoji structure.
apps/ui/src/components/blockkit/elements/Button.svelte (1)
39-95: CSS-based button variants are a clean improvement.The class mapping plus scoped styles keep behaviour intact while centralising presentation.
apps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte (1)
16-54: Styling refactor is tidy and consistent.The wrapper/label structure and scoped CSS align well with the new BEM styling approach.
apps/ui/src/components/blockkit/blocks/HeaderBlock.svelte (1)
12-12: Font size bump looks fine.The larger header size is straightforward and low-risk.
apps/ui/src/components/blockkit/context.ts (1)
1-40: Emoji shortcode resolution in renderText is a nice enhancement.Keeps the plain-text path intact while adding simple emoji support.
packages/mrkdwn/src/index.ts (1)
3-3: Public API export for renderEmoji makes sense.This aligns with the new emoji rendering utilities.
packages/mrkdwn/src/mrkdwn-to-html.test.ts (1)
149-159: LGTM!The updated test expectations correctly reflect the new emoji rendering structure with
c-emojiBEM classes, accessibility attributes (aria-label), and tooltip markup. The assertions align with therenderEmojiimplementation inemoji.ts.apps/ui/src/components/blockkit/BlockKitRenderer.svelte (1)
71-124: LGTM on the wrapper structure refactor.The BEM-like naming convention (
p-block_kit_renderer,p-block_kit_renderer__block_wrapper) provides good semantic structure. The flex container styling is appropriate for vertical block stacking.packages/mrkdwn/src/emoji.ts (1)
28-35: LGTM on the emoji rendering implementation.The expanded
renderEmojifunction correctly handles the optionallargeflag, includes proper accessibility attributes (aria-label,data-stringify-type), and maintains backward compatibility by keeping the parameter optional.apps/ui/src/components/blockkit/elements/StaticSelect.svelte (1)
74-99: LGTM on the CSS-based styling refactor.The migration from inline Tailwind classes to a dedicated
<style>block with BEM-like naming (c-select_input,c-select_input--compact) improves maintainability and aligns with the broader styling refactor in this PR. The custom dropdown arrow SVG and focus states are well implemented.apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte (4)
73-80: LGTM on emoji-only detection logic.The
isEmojiOnlyfunction correctly identifies sections containing only emoji elements and optional whitespace, enabling proper large emoji rendering.
96-107: LGTM on emoji rendering with fallback chain.The rendering logic provides a robust fallback chain:
renderEmoji→resolveEmoji→ unicode conversion → placeholder text. This ensures emoji display even when the emoji library doesn't recognise a shortcode.
185-187: Appropriate use of{@html}for sanitised content.The
{@htmlrenderBlock(block)}correctly uses the@htmldirective for rendering the DOMPurify-sanitised mrkdwn content. This aligns with the project guidelines.
305-347: These emoji tooltip styles are not duplicates and should not be consolidated.The
.c-emojistyles inRichTextBlock.svelte(scoped to.p-rich_text_block) andapp.css(scoped to.mrkdwn) are intentionally different implementations serving distinct visual contexts. They use different visibility mechanisms (display vs visibility/opacity), different spacing calculations, and different styling approaches. The RichTextBlock variant includes additional properties likebackground,border-radius,z-index, and the.c-emoji__largemodifier that are specific to that component. Consolidation would either lose functionality or require more complex selectors to achieve the same contextual behaviour.Likely an incorrect or invalid review comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/ui/src/components/blockkit/BlockKitRenderer.svelte`:
- Around line 73-76: The conditional class binding
"class:p-block_kit_renderer__block_wrapper--first={index === 0}" in
BlockKitRenderer.svelte is unused; remove that modifier binding from the div
with class "p-block_kit_renderer__block_wrapper" (or alternatively add a
matching CSS rule for ".p-block_kit_renderer__block_wrapper--first" in this
component's style block if the modifier is intended to have styles). Ensure you
update any tests or references to "p-block_kit_renderer__block_wrapper--first"
accordingly.
In `@apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte`:
- Around line 132-133: The aria-label in the MRKDWN_BR constant uses the literal
HTML entity " " which will be read literally by screen readers; update the
MRKDWN_BR definition in RichTextBlock.svelte to use a real non‑breaking space
character (e.g. '\u00A0') or replace the aria-label with an empty string (or
remove the aria-label entirely) so assistive tech sees the intended spacing
rather than the entity text.
In `@apps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte`:
- Line 12: The WorkspaceSelect.svelte component currently renames the incoming
prop to _onChange and never calls it, which breaks ActionsBlock's onChange
callbacks; change the prop binding to keep the original name (onChange) and
invoke it from the select change handler (or from the component's change
dispatcher) when the user picks a workspace (e.g., call onChange(event or
selectedValue) inside the select's on:change handler), or if selects are
intentionally non-interactive, remove the onChange prop from the component API
and from ActionsBlock usage to avoid a misleading prop.
---
Nitpick comments:
In `@apps/ui/src/components/blockkit/BlockKitRenderer.svelte`:
- Around line 15-16: Change the relative import from src/lib to use the $lib
alias: replace the import that currently reads from '../../lib/types' with an
import from '$lib/types' (leave local imports like './context' unchanged);
update any other imports in BlockKitRenderer.svelte that reference src/lib to
use the $lib alias so the TypeScript types (e.g., the imported types) resolve
via the path alias.
In `@apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte`:
- Around line 4-9: Update the import path in RichTextBlock.svelte to use the
$lib alias: replace the relative import '../../../lib/types' that brings in
RichTextBlockElement, RichTextInlineElement, RichTextStyle, and
SlackRichTextBlock with an alias import from '$lib/types' so the types are
imported via the project path alias.
In `@apps/ui/src/components/blockkit/elements/StaticSelect.svelte`:
- Around line 2-6: Replace the relative import of types with the $lib alias:
change the import of SlackStaticSelectElement and SlackOption from
'../../../lib/types' to '$lib/types' while keeping the renderText import as-is;
update the import statement that references SlackStaticSelectElement and
SlackOption so it uses the $lib path alias.
In `@packages/mrkdwn/src/emoji.ts`:
- Around line 34-35: The BEM naming for the large modifier is incorrect: change
the class construction in the cls assignment (which currently uses
c-emoji__large) to use the modifier convention c-emoji--large when
options?.large is true, and update any usages and styles that reference
c-emoji__large (e.g., selectors in RichTextBlock.svelte and related stylesheets)
to the new c-emoji--large to keep markup and CSS consistent with BEM.
apps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
apps/ui/src/components/blockkit/BlockKitRenderer.svelteapps/ui/src/components/blockkit/blocks/ActionsBlock.svelteapps/ui/src/components/blockkit/blocks/InputBlock.svelteapps/ui/src/components/blockkit/blocks/SectionBlock.svelteapps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte
🧰 Additional context used
📓 Path-based instructions (2)
**/*.svelte
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.svelte: Use{@html}in Svelte for mrkdwn rendering (ESLint rule disabled for this specific use case)
Use Svelte 5 runes ($state,$derived,$effect) for reactivity instead of legacy stores
Files:
apps/ui/src/components/blockkit/BlockKitRenderer.svelteapps/ui/src/components/blockkit/blocks/InputBlock.svelteapps/ui/src/components/blockkit/blocks/SectionBlock.svelteapps/ui/src/components/blockkit/blocks/ActionsBlock.svelteapps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte
apps/ui/src/**/*.{ts,tsx,svelte}
📄 CodeRabbit inference engine (CLAUDE.md)
Use
$libpath alias when importing fromsrc/lib/in Svelte applications
Files:
apps/ui/src/components/blockkit/BlockKitRenderer.svelteapps/ui/src/components/blockkit/blocks/InputBlock.svelteapps/ui/src/components/blockkit/blocks/SectionBlock.svelteapps/ui/src/components/blockkit/blocks/ActionsBlock.svelteapps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte
🧠 Learnings (1)
📚 Learning: 2026-01-14T21:36:07.933Z
Learnt from: tyom
Repo: tyom/botarium PR: 1
File: apps/ui/src/components/MessagePanel.svelte:10-23
Timestamp: 2026-01-14T21:36:07.933Z
Learning: In the client-only Botarium UI (Vite + Svelte), do not add or rely on SSR-specific guards (e.g., checks for sessionStorage) in components. Since the app runs only in Electron or the browser, code that accesses browser APIs will execute in a non-SSR environment, so SSR-unsafe checks are unnecessary and can be removed for maintainability.
Applied to files:
apps/ui/src/components/blockkit/BlockKitRenderer.svelteapps/ui/src/components/blockkit/blocks/InputBlock.svelteapps/ui/src/components/blockkit/blocks/SectionBlock.svelteapps/ui/src/components/blockkit/blocks/ActionsBlock.svelteapps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte
🔇 Additional comments (4)
apps/ui/src/components/blockkit/blocks/ActionsBlock.svelte (1)
32-111: ActionsBlock layout refactor looks tidy.The new wrapper structure and spacing read cleanly and should be easy to style consistently.
apps/ui/src/components/blockkit/blocks/SectionBlock.svelte (1)
101-101: WorkspaceSelect usage matches the updated API.The simplified props here align with the new component contract.
apps/ui/src/components/blockkit/blocks/InputBlock.svelte (1)
176-176: WorkspaceSelect usage aligns with the simplified props.This now matches the new component interface.
apps/ui/src/components/blockkit/BlockKitRenderer.svelte (1)
71-122: Wrapper container styling is clear and consistent.The new
p-block_kit_rendererand per-block wrapper structure is neat and keeps layout concerns centralised.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@apps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte`:
- Around line 11-21: WorkspaceSelect currently drops the onChange prop and
renders only a non-interactive wrapper (see WorkspaceSelect, the removed
onChange prop and the markup using class "c-select_input__wrapper" and
renderText(placeholder)), which removes interactivity for any forms using it;
either restore a real interactive control and the onChange handler so selections
emit actions and update form state (reintroduce the onChange prop, wire it to
the select/input element and dispatch changes) or explicitly mark the component
as read-only by adding appropriate accessibility attributes and styling
(aria-readonly/aria-disabled, a visual disabled style like class
"c-select_input--compact" + disabled state) and update the component API/docs to
reflect that it is display-only.
Use resolveEmoji() from @botarium/mrkdwn to convert emoji names to Unicode characters, with fallback to Slack's hex unicode field, then to :name: text for custom emojis.
Match Slack's actual HTML structure, class naming (BEM with c-/p- prefixes), and rendering behavior for rich text blocks and interactive elements. Rich text changes: - Bold/strike tags: <strong>→<b>, <del>→<s> - Newlines: \n→c-mrkdwn__br spacer spans (matching Slack) - Emojis: c-emoji class with tooltips, large variant for emoji-only sections - Pre/quote/list elements use Slack's actual class names and data attributes - Wrapper structure: p-block_kit_renderer__block_wrapper around each block - Skip whitespace-only sections between block elements Extract inline Tailwind → scoped CSS (Slack BEM naming): - Button: c-button with --outline/--primary/--danger modifiers - StaticSelect/WorkspaceSelect: c-select_input - ActionsBlock: p-actions_block with p-actions_block__action wrappers - ContextActionsBlock: p-context_actions - BlockKitRenderer: p-block_kit_renderer Also export renderEmoji from @botarium/mrkdwn with c-emoji class naming.
Slack resolves :emoji: shortcodes in all text fields including plain_text. renderText() was returning raw text without resolution, causing shortcodes like 📰 to appear as literal text in headers, buttons, labels, and other plain_text contexts. Also bump header block text size from lg to xl.
Remove unstyled `--first` modifier from BlockKitRenderer and unused `onChange` prop from WorkspaceSelect (display-only stub).
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/ui/src/components/blockkit/context.ts (1)
1-7:⚠️ Potential issue | 🟡 MinorSwitch the types import to the
$libalias. This keeps app imports consistent and resilient to path moves. As per coding guidelines,apps/ui/src/**/*.{ts,tsx,svelte}: Use$libpath alias when importing fromsrc/lib/in Svelte applications.💡 Suggested change
-import type { - SlackViewTextObject, - SlackOption, - UploadedFile, -} from '../../lib/types' +import type { + SlackViewTextObject, + SlackOption, + UploadedFile, +} from '$lib/types'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/ui/src/components/blockkit/context.ts` around lines 1 - 7, The import of types SlackViewTextObject, SlackOption, and UploadedFile in components/blockkit/context.ts uses a relative path ('../../lib/types'); change that import to use the Svelte $lib alias (e.g., '$lib/types') so the file imports consistently and is resilient to path moves; update the import statement that references these type symbols to import from '$lib/types' instead of '../../lib/types'.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
apps/ui/src/app.cssapps/ui/src/components/blockkit/BlockKitRenderer.svelteapps/ui/src/components/blockkit/blocks/ActionsBlock.svelteapps/ui/src/components/blockkit/blocks/ContextActionsBlock.svelteapps/ui/src/components/blockkit/blocks/HeaderBlock.svelteapps/ui/src/components/blockkit/blocks/InputBlock.svelteapps/ui/src/components/blockkit/blocks/RichTextBlock.svelteapps/ui/src/components/blockkit/blocks/SectionBlock.svelteapps/ui/src/components/blockkit/context.tsapps/ui/src/components/blockkit/elements/Button.svelteapps/ui/src/components/blockkit/elements/StaticSelect.svelteapps/ui/src/components/blockkit/elements/WorkspaceSelect.sveltebunfig.tomlpackages/mrkdwn/src/emoji.tspackages/mrkdwn/src/index.tspackages/mrkdwn/src/mrkdwn-to-html.test.ts
💤 Files with no reviewable changes (1)
- bunfig.toml
🚧 Files skipped from review as they are similar to previous changes (7)
- apps/ui/src/components/blockkit/blocks/ContextActionsBlock.svelte
- apps/ui/src/components/blockkit/elements/Button.svelte
- apps/ui/src/components/blockkit/blocks/SectionBlock.svelte
- apps/ui/src/components/blockkit/blocks/HeaderBlock.svelte
- packages/mrkdwn/src/mrkdwn-to-html.test.ts
- apps/ui/src/components/blockkit/BlockKitRenderer.svelte
- packages/mrkdwn/src/index.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js,jsx}: Use camelCase for variable names in TypeScript/JavaScript code
No semicolons in code, enforced by Prettier
Use single quotes instead of double quotes
Use trailing commas in es5 format
Prefix unused variables with underscore (_)
Files:
apps/ui/src/components/blockkit/context.tspackages/mrkdwn/src/emoji.ts
apps/ui/src/**/*.{ts,tsx,svelte}
📄 CodeRabbit inference engine (CLAUDE.md)
Use
$libpath alias when importing fromsrc/lib/in Svelte applications
Files:
apps/ui/src/components/blockkit/context.tsapps/ui/src/components/blockkit/elements/WorkspaceSelect.svelteapps/ui/src/components/blockkit/elements/StaticSelect.svelteapps/ui/src/components/blockkit/blocks/RichTextBlock.svelteapps/ui/src/components/blockkit/blocks/ActionsBlock.svelteapps/ui/src/components/blockkit/blocks/InputBlock.svelte
**/*.svelte
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.svelte: Use{@html}in Svelte for mrkdwn rendering (ESLint rule disabled for this specific use case)
Use Svelte 5 runes ($state,$derived,$effect) for reactivity instead of legacy stores
Files:
apps/ui/src/components/blockkit/elements/WorkspaceSelect.svelteapps/ui/src/components/blockkit/elements/StaticSelect.svelteapps/ui/src/components/blockkit/blocks/RichTextBlock.svelteapps/ui/src/components/blockkit/blocks/ActionsBlock.svelteapps/ui/src/components/blockkit/blocks/InputBlock.svelte
packages/mrkdwn/src/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Slack mrkdwn converter must provide bidirectional conversion (mrkdwn to HTML and Markdown to mrkdwn)
Files:
packages/mrkdwn/src/emoji.ts
🧠 Learnings (3)
📚 Learning: 2026-02-20T00:31:35.696Z
Learnt from: CR
Repo: tyom/botarium PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-20T00:31:35.696Z
Learning: Applies to packages/mrkdwn/src/**/*.ts : Slack mrkdwn converter must provide bidirectional conversion (mrkdwn to HTML and Markdown to mrkdwn)
Applied to files:
apps/ui/src/components/blockkit/context.tsapps/ui/src/components/blockkit/blocks/RichTextBlock.sveltepackages/mrkdwn/src/emoji.ts
📚 Learning: 2026-02-20T00:31:35.696Z
Learnt from: CR
Repo: tyom/botarium PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-20T00:31:35.696Z
Learning: Applies to **/*.svelte : Use `{html}` in Svelte for mrkdwn rendering (ESLint rule disabled for this specific use case)
Applied to files:
apps/ui/src/components/blockkit/context.tsapps/ui/src/components/blockkit/blocks/RichTextBlock.svelte
📚 Learning: 2026-01-14T21:36:07.933Z
Learnt from: tyom
Repo: tyom/botarium PR: 1
File: apps/ui/src/components/MessagePanel.svelte:10-23
Timestamp: 2026-01-14T21:36:07.933Z
Learning: In the client-only Botarium UI (Vite + Svelte), do not add or rely on SSR-specific guards (e.g., checks for sessionStorage) in components. Since the app runs only in Electron or the browser, code that accesses browser APIs will execute in a non-SSR environment, so SSR-unsafe checks are unnecessary and can be removed for maintainability.
Applied to files:
apps/ui/src/components/blockkit/elements/WorkspaceSelect.svelteapps/ui/src/components/blockkit/elements/StaticSelect.svelteapps/ui/src/components/blockkit/blocks/RichTextBlock.svelteapps/ui/src/components/blockkit/blocks/ActionsBlock.svelteapps/ui/src/components/blockkit/blocks/InputBlock.svelte
🔇 Additional comments (8)
apps/ui/src/components/blockkit/blocks/ActionsBlock.svelte (1)
32-111: Wrapper refactor looks clean and keeps action wiring intact. The new container and per-action wrapper should make spacing easier to manage without changing behaviour.apps/ui/src/components/blockkit/elements/StaticSelect.svelte (1)
51-99: Class-based styling and compact modifier read well. Behaviour is preserved and the template is simpler.apps/ui/src/app.css (1)
395-448: Emoji selector updates match the new c-emoji markup. Styling changes look consistent with the updated DOM.apps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte (1)
14-52: Wrapper + label styling looks consistent with other selects. Nice consolidation into dedicated classes.apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte (3)
17-107: Sanitiser updates and emoji rendering flow look well-aligned. The expanded allowlist supports the new emoji/stringify attributes without losing sanitisation.
139-173: Block rendering updates (pre/quote/list) read consistently with the new class structure.
185-347: Styling updates align well with the revised rich-text structure and emoji tooltips.apps/ui/src/components/blockkit/blocks/InputBlock.svelte (1)
174-176: WorkspaceSelect is intentionally display-only; the onChange prop was removed as dead code and should not be restored.The WorkspaceSelect component does not accept event handlers by design and was explicitly fixed to remove the unused onChange prop (git commit: "fix: remove unused class modifier and dead onChange prop in Block Kit"). This is consistent across all block types (InputBlock, SectionBlock, ActionsBlock), where workspace select elements render as read-only display components. No form state propagation is required for this component type.
Likely an incorrect or invalid review comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte`:
- Around line 132-137: Rename the constant MRKDWN_BR to a camelCase name (e.g.,
mrkdwnBr) and update all references accordingly (the constant declaration and
its use inside the newlinesToBreaks function) so the symbol name follows the
project's camelCase rule; ensure only the identifier is changed and the string
value and newlinesToBreaks(html: string) behavior remain identical.
In `@packages/mrkdwn/src/emoji.ts`:
- Around line 28-35: renderEmoji currently interpolates the untrusted name into
HTML (aria-label, inner tooltip code), so escape the name before embedding to
prevent markup breaking or injection: in renderEmoji (and where resolveEmoji is
used) compute an escapedName = escapeHtml(name) (or use the project's
HTML-escaping util) and use escapedName for aria-label and the tooltip code
text, while keeping the resolved emoji glyph as-is; ensure both the attribute
value (aria-label, data-* if needed) and the visible/text tooltip content use
the escaped string.
---
Outside diff comments:
In `@apps/ui/src/components/blockkit/context.ts`:
- Around line 1-7: The import of types SlackViewTextObject, SlackOption, and
UploadedFile in components/blockkit/context.ts uses a relative path
('../../lib/types'); change that import to use the Svelte $lib alias (e.g.,
'$lib/types') so the file imports consistently and is resilient to path moves;
update the import statement that references these type symbols to import from
'$lib/types' instead of '../../lib/types'.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/mrkdwn/src/emoji.ts (1)
36-36: Use BEM modifier syntax--largeinstead of element syntax__largefor consistency with Slack's CSS naming convention.Slack's documented BEM-like class naming uses
__for child elements (e.g.,c-emoji__tooltip) and--for modifiers and variants (e.g.,c-emoji--small). Thelargeoption is a variant modifier of the component, not a child element, so it should use--rather than__to align with Slack's convention and the existing element classes in this file.♻️ Corrected BEM naming
- const cls = options?.large ? 'c-emoji c-emoji__large' : 'c-emoji' + const cls = options?.large ? 'c-emoji c-emoji--large' : 'c-emoji'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mrkdwn/src/emoji.ts` at line 36, The class name for the large modifier uses element syntax; update the assignment that computes cls (the const cls = options?.large ? 'c-emoji c-emoji__large' : 'c-emoji') to use BEM modifier syntax 'c-emoji--large' instead of 'c-emoji__large' so the large variant becomes 'c-emoji c-emoji--large'; adjust the string in the emoji.ts cls computation (and any other occurrences of 'c-emoji__large' in that module) to 'c-emoji--large'.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/ui/src/components/blockkit/blocks/RichTextBlock.sveltepackages/mrkdwn/src/emoji.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js,jsx}: Use camelCase for variable names in TypeScript/JavaScript code
No semicolons in code, enforced by Prettier
Use single quotes instead of double quotes
Use trailing commas in es5 format
Prefix unused variables with underscore (_)
Files:
packages/mrkdwn/src/emoji.ts
packages/mrkdwn/src/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Slack mrkdwn converter must provide bidirectional conversion (mrkdwn to HTML and Markdown to mrkdwn)
Files:
packages/mrkdwn/src/emoji.ts
🧠 Learnings (1)
📚 Learning: 2026-02-20T00:31:35.696Z
Learnt from: CR
Repo: tyom/botarium PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-20T00:31:35.696Z
Learning: Applies to packages/mrkdwn/src/**/*.ts : Slack mrkdwn converter must provide bidirectional conversion (mrkdwn to HTML and Markdown to mrkdwn)
Applied to files:
packages/mrkdwn/src/emoji.ts
🧬 Code graph analysis (1)
packages/mrkdwn/src/emoji.ts (2)
packages/mrkdwn/src/index.ts (2)
renderEmoji(3-3)resolveEmoji(3-3)packages/mrkdwn/src/utils.ts (1)
escapeHtml(2-8)
🔇 Additional comments (2)
packages/mrkdwn/src/emoji.ts (2)
35-37: Good fix for the HTML injection concern.The use of
escapeHtmlto sanitise the emoji name before interpolation intoaria-labeland the tooltip text correctly addresses the previous security review. The escaped characters (&,<,>,") are appropriate for both attribute and text contexts.
29-32: LGTM on the expanded signature.The optional
{ large?: boolean }parameter cleanly extends the API for emoji-only sections without breaking existing callers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/mrkdwn/src/emoji.ts`:
- Line 36: The class name for the large modifier uses element syntax; update the
assignment that computes cls (the const cls = options?.large ? 'c-emoji
c-emoji__large' : 'c-emoji') to use BEM modifier syntax 'c-emoji--large' instead
of 'c-emoji__large' so the large variant becomes 'c-emoji c-emoji--large';
adjust the string in the emoji.ts cls computation (and any other occurrences of
'c-emoji__large' in that module) to 'c-emoji--large'.
Summary by CodeRabbit
New Features
Style / Refactor
Bug Fixes
Tests
Chores