Skip to content

Comments

Block Kit improvements#11

Merged
tyom merged 5 commits intomainfrom
dev
Feb 21, 2026
Merged

Block Kit improvements#11
tyom merged 5 commits intomainfrom
dev

Conversation

@tyom
Copy link
Owner

@tyom tyom commented Feb 21, 2026

Summary by CodeRabbit

  • New Features

    • Enhanced emoji rendering with interactive tooltips and optional large-size display
    • Improved rich text rendering with better list indentation, emoji support and styling
  • Style / Refactor

    • Modernised CSS naming and consolidated component styling
    • Updated block and element layout wrappers and increased header font size
  • Bug Fixes

    • Workspace-select components no longer forward previous change callbacks, altering selection behaviour
  • Tests

    • Updated emoji rendering tests
  • Chores

    • Removed test configuration comment

@coderabbitai
Copy link

coderabbitai bot commented Feb 21, 2026

📝 Walkthrough

Walkthrough

Replaces 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

Cohort / File(s) Summary
Global CSS
apps/ui/src/app.css
Renamed emoji selectors from .s-* to .c-*, updated tooltip selectors and hover rules, and increased tooltip font-size (48px → 64px).
BlockKit renderer & wrappers
apps/ui/src/components/blockkit/BlockKitRenderer.svelte
Replaced top-level classes with p-block_kit_renderer, wrapped each block in p-block_kit_renderer__block_wrapper; rendering branches preserved.
Actions & Context layout
apps/ui/src/components/blockkit/blocks/ActionsBlock.svelte, apps/ui/src/components/blockkit/blocks/ContextActionsBlock.svelte
Introduced semantic wrappers (p-actions_block, p-actions_block_elements, p-actions_block__action, p-context_actions) and local styles; adjusted DOM structure and minor event wiring (WorkspaceSelect no longer receives onChange).
Rich text, lists & emoji rendering
apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte, apps/ui/src/components/blockkit/context.ts
Integrated renderEmoji/resolveEmoji, added emoji-only detection (large emoji), extended sanitiser attrs, replaced pre/quote/list markup and classes, and added CSS for emoji/tooltip and list indentation.
mrkdwn emoji API & tests
packages/mrkdwn/src/emoji.ts, packages/mrkdwn/src/index.ts, packages/mrkdwn/src/mrkdwn-to-html.test.ts
Added renderEmoji(name, { large?: boolean }), updated HTML to c-emoji/c-emoji__tooltip with aria-label and data-stringify-type, exported renderEmoji, and updated tests to expect new structure.
Form controls styling & API change
apps/ui/src/components/blockkit/elements/Button.svelte, apps/ui/src/components/blockkit/elements/StaticSelect.svelte, apps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte
Moved styling from inline classes to CSS-driven BEM classes (c-button, c-select_input, etc.); removed onChange prop from WorkspaceSelect public Props and updated markup.
Blocks removing WorkspaceSelect callbacks
apps/ui/src/components/blockkit/blocks/InputBlock.svelte, apps/ui/src/components/blockkit/blocks/SectionBlock.svelte
WorkspaceSelect invocations for workspace-select accessories no longer pass onChange, removing previous onInput/onAction propagation for those selects.
Minor tweaks & config
apps/ui/src/components/blockkit/blocks/HeaderBlock.svelte, bunfig.toml
Header font-size increased (text-lgtext-xl); removed a test comment line from bunfig.toml.

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)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is vague and generic, using a broad term 'improvements' without clarifying the specific nature or scope of the Block Kit changes. Consider a more specific title such as 'Refactor Block Kit styling to CSS-based approach' or 'Update Block Kit components with emoji support and improved styling' to better convey the main changes.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte (1)

4-9: Use $lib alias for imports from src/lib/.

As per coding guidelines, imports from src/lib/ should use the $lib path 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 $lib alias for imports from src/lib/.

As per coding guidelines, imports from src/lib/ should use the $lib path 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 $lib alias for imports from src/lib/.

As per coding guidelines, imports from src/lib/ should use the $lib path 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__large uses 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 be c-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.svelte and 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

📥 Commits

Reviewing files that changed from the base of the PR and between 6ac4f7c and 92eabd8.

📒 Files selected for processing (14)
  • apps/ui/src/app.css
  • apps/ui/src/components/blockkit/BlockKitRenderer.svelte
  • apps/ui/src/components/blockkit/blocks/ActionsBlock.svelte
  • apps/ui/src/components/blockkit/blocks/ContextActionsBlock.svelte
  • apps/ui/src/components/blockkit/blocks/HeaderBlock.svelte
  • apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte
  • apps/ui/src/components/blockkit/context.ts
  • apps/ui/src/components/blockkit/elements/Button.svelte
  • apps/ui/src/components/blockkit/elements/StaticSelect.svelte
  • apps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte
  • bunfig.toml
  • packages/mrkdwn/src/emoji.ts
  • packages/mrkdwn/src/index.ts
  • packages/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.svelte
  • apps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte
  • apps/ui/src/components/blockkit/blocks/HeaderBlock.svelte
  • apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte
  • apps/ui/src/components/blockkit/BlockKitRenderer.svelte
  • apps/ui/src/components/blockkit/blocks/ContextActionsBlock.svelte
  • apps/ui/src/components/blockkit/blocks/ActionsBlock.svelte
  • apps/ui/src/components/blockkit/elements/StaticSelect.svelte
apps/ui/src/**/*.{ts,tsx,svelte}

📄 CodeRabbit inference engine (CLAUDE.md)

Use $lib path alias when importing from src/lib/ in Svelte applications

Files:

  • apps/ui/src/components/blockkit/elements/Button.svelte
  • apps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte
  • apps/ui/src/components/blockkit/blocks/HeaderBlock.svelte
  • apps/ui/src/components/blockkit/context.ts
  • apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte
  • apps/ui/src/components/blockkit/BlockKitRenderer.svelte
  • apps/ui/src/components/blockkit/blocks/ContextActionsBlock.svelte
  • apps/ui/src/components/blockkit/blocks/ActionsBlock.svelte
  • apps/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.ts
  • packages/mrkdwn/src/index.ts
  • apps/ui/src/components/blockkit/context.ts
  • packages/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.ts
  • packages/mrkdwn/src/index.ts
  • packages/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.ts naming 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.svelte
  • apps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte
  • apps/ui/src/components/blockkit/blocks/HeaderBlock.svelte
  • apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte
  • apps/ui/src/components/blockkit/BlockKitRenderer.svelte
  • apps/ui/src/components/blockkit/blocks/ContextActionsBlock.svelte
  • apps/ui/src/components/blockkit/blocks/ActionsBlock.svelte
  • apps/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.ts
  • packages/mrkdwn/src/index.ts
  • apps/ui/src/components/blockkit/context.ts
  • packages/mrkdwn/src/mrkdwn-to-html.test.ts
  • apps/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.ts
  • apps/ui/src/components/blockkit/context.ts
  • packages/mrkdwn/src/mrkdwn-to-html.test.ts
  • apps/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-emoji BEM classes, accessibility attributes (aria-label), and tooltip markup. The assertions align with the renderEmoji implementation in emoji.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 renderEmoji function correctly handles the optional large flag, 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 isEmojiOnly function 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: renderEmojiresolveEmoji → 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 {@html renderBlock(block)} correctly uses the @html directive 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-emoji styles in RichTextBlock.svelte (scoped to .p-rich_text_block) and app.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 like background, border-radius, z-index, and the .c-emoji__large modifier 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 "&nbsp;" 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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 92eabd8 and 103ec19.

📒 Files selected for processing (5)
  • apps/ui/src/components/blockkit/BlockKitRenderer.svelte
  • apps/ui/src/components/blockkit/blocks/ActionsBlock.svelte
  • apps/ui/src/components/blockkit/blocks/InputBlock.svelte
  • apps/ui/src/components/blockkit/blocks/SectionBlock.svelte
  • apps/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.svelte
  • apps/ui/src/components/blockkit/blocks/InputBlock.svelte
  • apps/ui/src/components/blockkit/blocks/SectionBlock.svelte
  • apps/ui/src/components/blockkit/blocks/ActionsBlock.svelte
  • apps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte
apps/ui/src/**/*.{ts,tsx,svelte}

📄 CodeRabbit inference engine (CLAUDE.md)

Use $lib path alias when importing from src/lib/ in Svelte applications

Files:

  • apps/ui/src/components/blockkit/BlockKitRenderer.svelte
  • apps/ui/src/components/blockkit/blocks/InputBlock.svelte
  • apps/ui/src/components/blockkit/blocks/SectionBlock.svelte
  • apps/ui/src/components/blockkit/blocks/ActionsBlock.svelte
  • apps/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.svelte
  • apps/ui/src/components/blockkit/blocks/InputBlock.svelte
  • apps/ui/src/components/blockkit/blocks/SectionBlock.svelte
  • apps/ui/src/components/blockkit/blocks/ActionsBlock.svelte
  • apps/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_renderer and 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.

tyom added 4 commits February 21, 2026 16:16
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).
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 | 🟡 Minor

Switch the types import to the $lib alias. This keeps app imports consistent and resilient to path moves. As per coding guidelines, apps/ui/src/**/*.{ts,tsx,svelte}: Use $lib path alias when importing from src/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

📥 Commits

Reviewing files that changed from the base of the PR and between 103ec19 and d681f03.

📒 Files selected for processing (16)
  • apps/ui/src/app.css
  • apps/ui/src/components/blockkit/BlockKitRenderer.svelte
  • apps/ui/src/components/blockkit/blocks/ActionsBlock.svelte
  • apps/ui/src/components/blockkit/blocks/ContextActionsBlock.svelte
  • apps/ui/src/components/blockkit/blocks/HeaderBlock.svelte
  • apps/ui/src/components/blockkit/blocks/InputBlock.svelte
  • apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte
  • apps/ui/src/components/blockkit/blocks/SectionBlock.svelte
  • apps/ui/src/components/blockkit/context.ts
  • apps/ui/src/components/blockkit/elements/Button.svelte
  • apps/ui/src/components/blockkit/elements/StaticSelect.svelte
  • apps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte
  • bunfig.toml
  • packages/mrkdwn/src/emoji.ts
  • packages/mrkdwn/src/index.ts
  • packages/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.ts
  • packages/mrkdwn/src/emoji.ts
apps/ui/src/**/*.{ts,tsx,svelte}

📄 CodeRabbit inference engine (CLAUDE.md)

Use $lib path alias when importing from src/lib/ in Svelte applications

Files:

  • apps/ui/src/components/blockkit/context.ts
  • apps/ui/src/components/blockkit/elements/WorkspaceSelect.svelte
  • apps/ui/src/components/blockkit/elements/StaticSelect.svelte
  • apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte
  • apps/ui/src/components/blockkit/blocks/ActionsBlock.svelte
  • apps/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.svelte
  • apps/ui/src/components/blockkit/elements/StaticSelect.svelte
  • apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte
  • apps/ui/src/components/blockkit/blocks/ActionsBlock.svelte
  • apps/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.ts
  • apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte
  • packages/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.ts
  • apps/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.svelte
  • apps/ui/src/components/blockkit/elements/StaticSelect.svelte
  • apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte
  • apps/ui/src/components/blockkit/blocks/ActionsBlock.svelte
  • apps/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'.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/mrkdwn/src/emoji.ts (1)

36-36: Use BEM modifier syntax --large instead of element syntax __large for 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). The large option 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

📥 Commits

Reviewing files that changed from the base of the PR and between d681f03 and cc8727f.

📒 Files selected for processing (2)
  • apps/ui/src/components/blockkit/blocks/RichTextBlock.svelte
  • packages/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 escapeHtml to sanitise the emoji name before interpolation into aria-label and 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'.

@tyom tyom merged commit bbe2493 into main Feb 21, 2026
2 checks passed
@tyom tyom deleted the dev branch February 21, 2026 16:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant