Skip to content

feat(core/chat): add new chat components - #2569

Merged
danielleroux merged 52 commits into
mainfrom
feat/chat-components
Jul 21, 2026
Merged

danielleroux merged 52 commits into
mainfrom
feat/chat-components

Conversation

@danielleroux

@danielleroux danielleroux commented May 27, 2026 •

Copy link
Copy Markdown
Collaborator

💡 What is the current behavior?

JIRA: IX-4307

🆕 What is the new behavior?

🏁 Checklist

A pull request can only be merged if all of these conditions are met (where applicable):

  • 🦮 Accessibility (a11y) features were implemented
  • 🗺️ Internationalization (i18n) - no hard coded strings
  • 📲 Responsiveness - components handle viewport changes and content overflow gracefully
  • 📕 Add or update a Storybook story
  • 📄 Documentation was reviewed/updated siemens/ix-docs
  • 🧪 Unit tests were added/updated and pass (pnpm test)
  • 📸 Visual regression tests were added/updated and pass (Guide)
  • 🧐 Static code analysis passes (pnpm lint)
  • 🏗️ Successful compilation (pnpm build, changes pushed)

👨‍💻 Help & support

Summary by CodeRabbit

  • New Features

    • Full chat UI suite: chat container, AI/user messages, chat input (multiline submit, processing state, follow-up prompts), attachment chips (preview, scroll, overflow), character-limit UI, and preview examples across frameworks and Storybook.
  • Bug Fixes

    • Close button remains usable on inactive chips without text overlap.
  • Documentation

    • Architecture docs updated and generated SDD artifacts ignored.
  • Tests

    • New accessibility, visual, regression tests and snapshots for chat features.

@changeset-bot

changeset-bot Bot commented May 27, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3c11bd6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
@siemens/ix Minor
@siemens/ix-angular Minor
@siemens/ix-docs Minor
@siemens/ix-react Minor
@siemens/ix-vue Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify

netlify Bot commented May 27, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for ix-storybook ready!

Name Link
🔨 Latest commit 3c11bd6
🔍 Latest deploy log https://app.netlify.com/projects/ix-storybook/deploys/6a588d36f5f83d0009386fe2
😎 Deploy Preview https://deploy-preview-2569--ix-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the new ix-chat component suite for AI prompt entry and conversation layouts, including ix-chat-input, ix-chat-prompt-attachment, ix-chat-user-message, and ix-chat-ai-message. It also includes a fix for ix-chip to ensure interactive close buttons render correctly when the chip is inactive. The review identified several critical issues in the new chat components, including missing lifecycle handling for observers on component re-attachment, incorrect state handling for the submit button during processing, premature form submission during IME composition, a missing key prop in dynamic lists, potential runtime TypeErrors with null/undefined file names, and a regression in the ix-chip pointer-events styling.

I am having trouble creating individual review comments. Click here to see my feedback.

packages/core/src/components/chat-input/chat-input.tsx (229-244)

high

The component does not implement connectedCallback to re-initialize the MutationObserver and ResizeObserver when the component is disconnected and re-attached to the DOM. This causes the observers to remain disconnected and breaks the attachment overflow and follow-up updates on re-attachment. Implementing connectedCallback with a guard flag ensures proper re-initialization.

  private hasDisconnected = false;

  connectedCallback() {
    if (this.hasDisconnected) {
      this.initAttachmentMutationObserver();
      if (this.attachmentsRef.current) {
        this.initAttachmentResizeObserver(this.attachmentsRef.current);
      }
      this.hasDisconnected = false;
    }
  }

  componentDidLoad() {
    this.updateHasFollowUp();
    this.initAttachmentMutationObserver();
    this.scheduleAttachmentOverflowUpdate();
    this.updateTextareaHeight();
  }

  componentDidRender() {
    this.scheduleAttachmentOverflowUpdate();
    this.updateTextareaHeight();
  }

  disconnectedCallback() {
    this.attachmentResizeObserver?.disconnect();
    this.attachmentMutationObserver?.disconnect();
    this.hasDisconnected = true;
  }

packages/core/src/components/chat-input/chat-input.tsx (292-315)

high

When state === 'processing', the submit button acts as a "Stop" button. However, canSubmit() does not check this.state, which means if the input is empty, the "Stop" button is disabled and cannot be clicked. Furthermore, if the input is not empty, clicking it or pressing Enter will submit the prompt again instead of stopping the processing. We should ensure the button is enabled during processing and handles the stop action correctly.

  private canSubmit() {
    return (
      !this.disabled &&
      !this.readonly &&
      (this.state === 'processing' ||
        ((this.value || '').trim().length > 0 &&
          !this.isCharacterLimitReached()))
    );
  }

  private emitIxChangeIfNeeded() {
    if (this.initialValue !== this.value) {
      this.ixChange.emit(this.value);
      this.initialValue = this.value;
    }
  }

  private submitPrompt() {
    if (this.state === 'processing') {
      this.promptSubmit.emit('');
      return;
    }

    if (!this.canSubmit()) {
      return;
    }

    this.emitIxChangeIfNeeded();
    this.promptSubmit.emit(this.value);
  }

packages/core/src/components/chat-input/chat-input.tsx (420-433)

medium

Pressing Enter while composing text in an IME (Input Method Editor) will trigger the keydown event and submit the prompt prematurely. We should check event.isComposing to prevent this.

  private handleKeyDown(event: KeyboardEvent) {
    if (
      event.key !== 'Enter' ||
      event.isComposing ||
      event.shiftKey ||
      event.altKey ||
      event.ctrlKey ||
      event.metaKey ||
      this.insertLineBreakOnEnter
    ) {
      return;
    }

    event.preventDefault();
    this.submitPrompt();
  }

packages/core/src/components/chat-input/chat-input.tsx (784-811)

medium

The dynamic list rendered by this.attachmentOverflowEntries.map is missing a key prop on the outer element. This can cause rendering and reconciliation issues when attachments are dynamically added or removed.

  private renderAttachmentOverflowItems() {
    return this.attachmentOverflowEntries.map((entry) => (
      <div
        key={entry.index}
        class="attachment-overflow-menu-item"
        data-attachment-overflow-generated
        data-attachment-overflow-label={entry.label}
      >
        <ix-dropdown-item
          class="attachment-overflow-generated-item"
          icon={entry.icon}
          ariaLabelButton={entry.label}
          onClick={() => this.handleAttachmentOverflowItemClick(entry.index)}
        >
          {entry.label}
        </ix-dropdown-item>
        {entry.canRemove && (
          <ix-icon-button
            aria-label={entry.removeAriaLabel}
            class="attachment-overflow-remove-button"
            icon={iconCloseSmall}
            size="24"
            variant="subtle-tertiary"
            onClick={(event: MouseEvent) =>
              this.handleAttachmentOverflowRemoveClick(event, entry.index)
            }
          ></ix-icon-button>
        )}
      </div>
    ));
  }

packages/core/src/components/chat-prompt-attachment/chat-prompt-attachment.tsx (75-87)

medium

If this.fileName is null or undefined, calling this.fileName.trim() will throw a runtime TypeError. We should guard against null/undefined values to ensure robust defensive programming.

  private splitFileName() {
    const fileName = (this.fileName || '').trim();
    const extensionStart = fileName.lastIndexOf('.');

    if (extensionStart <= 0 || extensionStart === fileName.length - 1) {
      return { name: fileName, extension: '' };
    }

    return {
      name: fileName.slice(0, extensionStart),
      extension: fileName.slice(extensionStart),
    };
  }

packages/core/src/components/chip/chip.scss (74-76)

medium

Removing pointer-events: none from :host(.inactive) and only applying it to .chip-main allows click events on the chip body to bubble up to the host. This means any click listeners on ix-chip will still be triggered even when the chip is inactive. A cleaner CSS-only solution is to keep pointer-events: none on :host(.inactive) and explicitly set pointer-events: auto on .chip-close.

:host(.inactive) {
  pointer-events: none;

  .chip-close {
    pointer-events: auto;
  }
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
packages/core/src/components/chat-input/chat-input.tsx (3)

536-538: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep the action button semantics in sync with component state.

When state === 'processing', the icon changes to a stop glyph, but the control still exposes aria-label="Submit prompt", and disabledSubmitButton stops honoring disabled/readonly. That leaves a disabled chat input with a focusable action button and the wrong accessible name.

Also applies to: 601-605

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/chat-input/chat-input.tsx` around lines 536 -
538, The action button's enabled/aria semantics must follow the component state:
update the disabledSubmitButton calculation to also disable the button when
this.state === 'processing' (not just !this.canSubmit() && this.state ===
'input'), and ensure submitButtonIcon and the button's accessible
name/aria-label change when processing (e.g., set aria-label to "Stop
processing" or similar when this.state === 'processing'); modify uses around
disabledSubmitButton, submitButtonIcon, and the button render (including the
code mirrored at 601-605) so the control is non-focusable/disabled and has the
correct aria-label while processing. Ensure references to canSubmit(),
submitButtonIcon, and this.state are updated consistently.

490-499: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Narrow the mutation observer to slot-relevant changes.

This observer listens to every attribute mutation in the host subtree. Because value is reflected, normal typing can retrigger updateHasFollowUp() and attachment scrollbar measurement on each keystroke, which pushes unnecessary layout work onto the main input path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/chat-input/chat-input.tsx` around lines 490 -
499, The mutation observer in initAttachmentMutationObserver is too broad and
reacts to reflected 'value' attribute changes; narrow it so typing doesn't
retrigger updateHasFollowUp() and scheduleAttachmentScrollbarUpdate(). Modify
the observe call on attachmentMutationObserver to either target the specific
attachment slot/container node instead of this.hostElement, or disable attribute
watching and rely on childList/subtree only, or supply attributeFilter that
excludes 'value' (e.g., attributes: true with attributeFilter: ['class','style',
...] but not 'value'); keep the callback and method names (updateHasFollowUp,
scheduleAttachmentScrollbarUpdate, attachmentMutationObserver,
initAttachmentMutationObserver) unchanged.

247-251: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Document or de-publicize getAssociatedFormElement().

@Method() makes this part of the element API, so /** @internal */ is misleading and the method is missing the required @since metadata. Either add the public JSDoc or remove @Method() if this is only for internal/test use. As per coding guidelines, "For new components, properties, methods, or events, include JSDocs with a @since tag indicating the version number in which it was added."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/chat-input/chat-input.tsx` around lines 247 -
251, The method getAssociatedFormElement is currently exposed via the `@Method`()
decorator but marked /** `@internal` */ without `@since` metadata; either document
it as a public API by replacing the internal JSDoc with a proper public JSDoc
including a `@since` tag and description, or de-publicize it by removing the
`@Method`() decorator so it remains internal (keeping the implementation that
returns this.formInternals.form). Update the JSDoc and/or decorator accordingly
to match the intended API surface.

Source: Coding guidelines

packages/core/src/components/chat-input/tests/chat-input.ct.ts (1)

29-383: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the required accessibility and hydration smoke coverage.

This new .ct.ts suite never runs an axe scan, has no 'renders' test, and starts querying/interacting with ix-chat-input immediately after mount() without first waiting for \bhydrated\b. That misses the repo’s required baseline coverage and makes the interaction tests more race-prone. As per coding guidelines, "Every test file should include an 'accessibility' test using makeAxeBuilder", "Every test file should include a 'renders' test verifying basic hydration", and "Always verify components are hydrated before making further assertions using await expect(page.locator('ix-component')).toHaveClass(/\bhydrated\b/)."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/chat-input/tests/chat-input.ct.ts` around lines
29 - 383, Add the required hydration "renders" test and an accessibility/axe
scan, and ensure every test waits for hydration before interacting: after
mounting use await
expect(page.locator('ix-chat-input')).toHaveClass(/\bhydrated\b/) (used
throughout) and add a regressionTest named 'renders' that mounts the component
and asserts hydrated, plus an 'accessibility' regressionTest that uses
makeAxeBuilder(page).include('ix-chat-input')/analyze to run axe on the
component; update other tests to wait for hydration immediately after mount
before querying or interacting with the element (references: regressionTest,
makeAxeBuilder, and the hydration assertion
expect(...).toHaveClass(/\bhydrated\b/)).

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/core/src/components/chat-input/chat-input.tsx`:
- Around line 536-538: The action button's enabled/aria semantics must follow
the component state: update the disabledSubmitButton calculation to also disable
the button when this.state === 'processing' (not just !this.canSubmit() &&
this.state === 'input'), and ensure submitButtonIcon and the button's accessible
name/aria-label change when processing (e.g., set aria-label to "Stop
processing" or similar when this.state === 'processing'); modify uses around
disabledSubmitButton, submitButtonIcon, and the button render (including the
code mirrored at 601-605) so the control is non-focusable/disabled and has the
correct aria-label while processing. Ensure references to canSubmit(),
submitButtonIcon, and this.state are updated consistently.
- Around line 490-499: The mutation observer in initAttachmentMutationObserver
is too broad and reacts to reflected 'value' attribute changes; narrow it so
typing doesn't retrigger updateHasFollowUp() and
scheduleAttachmentScrollbarUpdate(). Modify the observe call on
attachmentMutationObserver to either target the specific attachment
slot/container node instead of this.hostElement, or disable attribute watching
and rely on childList/subtree only, or supply attributeFilter that excludes
'value' (e.g., attributes: true with attributeFilter: ['class','style', ...] but
not 'value'); keep the callback and method names (updateHasFollowUp,
scheduleAttachmentScrollbarUpdate, attachmentMutationObserver,
initAttachmentMutationObserver) unchanged.
- Around line 247-251: The method getAssociatedFormElement is currently exposed
via the `@Method`() decorator but marked /** `@internal` */ without `@since` metadata;
either document it as a public API by replacing the internal JSDoc with a proper
public JSDoc including a `@since` tag and description, or de-publicize it by
removing the `@Method`() decorator so it remains internal (keeping the
implementation that returns this.formInternals.form). Update the JSDoc and/or
decorator accordingly to match the intended API surface.

In `@packages/core/src/components/chat-input/tests/chat-input.ct.ts`:
- Around line 29-383: Add the required hydration "renders" test and an
accessibility/axe scan, and ensure every test waits for hydration before
interacting: after mounting use await
expect(page.locator('ix-chat-input')).toHaveClass(/\bhydrated\b/) (used
throughout) and add a regressionTest named 'renders' that mounts the component
and asserts hydrated, plus an 'accessibility' regressionTest that uses
makeAxeBuilder(page).include('ix-chat-input')/analyze to run axe on the
component; update other tests to wait for hydration immediately after mount
before querying or interacting with the element (references: regressionTest,
makeAxeBuilder, and the hydration assertion
expect(...).toHaveClass(/\bhydrated\b/)).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 94a290fd-805b-4df7-83b0-6c5d8859e8d8

📥 Commits

Reviewing files that changed from the base of the PR and between 6482acd and 3e8f855.

📒 Files selected for processing (7)
  • packages/angular/src/components.ts
  • packages/angular/standalone/src/components.ts
  • packages/core/src/components.d.ts
  • packages/core/src/components/chat-input/chat-input.tsx
  • packages/core/src/components/chat-input/tests/chat-input.ct.ts
  • packages/react/src/components/components.server.ts
  • packages/vue/src/components/ix-chat-input.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/components/chat-input/tests/chat-input.ct.ts (1)

75-75: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Follow defensive class-matching patterns to prevent partial matches.

Several class assertions do not follow the required patterns from the coding guidelines:

  • Non-hyphenated classes (e.g., disabled) should use word boundaries: /\bdisabled\b/
  • Hyphenated classes (e.g., has-attachments, character-limit--hard) should use negative lookahead: /has-attachments(?!-)/

Current patterns like /has-attachments/ would incorrectly match has-attachments-overflow if such a class were added later.

Affected lines:

  • Line 75: /disabled/ → /\bdisabled\b/
  • Line 244: /character-limit--hard/ → /character-limit--hard(?!-)/
  • Line 285: /has-attachments/ → /has-attachments(?!-)/
  • Line 287: /attachments--scroll/ → /attachments--scroll(?!-)/
  • Lines 291, 317, 325, 349: /has-attachment-scrollbar/ → /has-attachment-scrollbar(?!-)/
  • Line 374: /has-follow-up/ → /has-follow-up(?!-)/

As per coding guidelines: "Use word boundary \b in regex patterns to avoid false matches when checking classes like hydrated" and "Use hyphenated class name assertions with negative lookahead to avoid partial matches (e.g., overflow-shadow must not match overflow-shadow-container)".

Also applies to: 244-244, 285-291, 317-317, 325-325, 349-349, 374-374

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/chat-input/tests/chat-input.ct.ts` at line 75,
Update the class-assertion regexes to use defensive patterns: replace /disabled/
with /\bdisabled\b/ for non-hyphenated classes and replace hyphenated checks
like /has-attachments/, /character-limit--hard/, /attachments--scroll/,
/has-attachment-scrollbar/, /has-follow-up/ with negative-lookahead forms (e.g.,
/has-attachments(?!-)/, /character-limit--hard(?!-)/, etc.) in the
chat-input.ct.ts tests — locate the assertions using variables like submitButton
and other class checks in the file and swap the raw substring regexes for the
appropriate /\b...\b/ or ...(?!-)/ forms to avoid partial matches.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/components/chat-input/chat-input.tsx`:
- Around line 536-541: handleKeyDown currently allows Enter to call submitPrompt
even when the component is processing; update the handler (handleKeyDown) to
early-return or skip invoking submitPrompt when this.state === 'processing' (in
addition to existing canSubmit() checks) so keyboard submission is blocked
during processing and duplicate promptSubmit events cannot be emitted.

---

Outside diff comments:
In `@packages/core/src/components/chat-input/tests/chat-input.ct.ts`:
- Line 75: Update the class-assertion regexes to use defensive patterns: replace
/disabled/ with /\bdisabled\b/ for non-hyphenated classes and replace hyphenated
checks like /has-attachments/, /character-limit--hard/, /attachments--scroll/,
/has-attachment-scrollbar/, /has-follow-up/ with negative-lookahead forms (e.g.,
/has-attachments(?!-)/, /character-limit--hard(?!-)/, etc.) in the
chat-input.ct.ts tests — locate the assertions using variables like submitButton
and other class checks in the file and swap the raw substring regexes for the
appropriate /\b...\b/ or ...(?!-)/ forms to avoid partial matches.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 19f80e9e-b956-4b46-babc-a6249274b2ea

📥 Commits

Reviewing files that changed from the base of the PR and between 3e8f855 and 9f0270f.

📒 Files selected for processing (2)
  • packages/core/src/components/chat-input/chat-input.tsx
  • packages/core/src/components/chat-input/tests/chat-input.ct.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/components/chat-input/chat-input.tsx (1)

415-429: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Add a regression test for Enter during processing.

This fixes the original bug, but the supplied component tests only cover Enter submission and the processing state separately. Please add a case that sets state="processing", presses Enter, and asserts that promptSubmit is not emitted, so this path cannot regress.

🧪 Suggested test shape
regressionTest(
  'ix-chat-input does not emit promptSubmit on Enter while processing',
  async ({ mount, page }) => {
    await mount(
      '<ix-chat-input state="processing" value="Analyze alarms"></ix-chat-input>'
    );

    await page.evaluate(() => {
      globalThis.__promptSubmitValue = undefined;
      document
        .querySelector('ix-chat-input')
        ?.addEventListener('promptSubmit', ((event: CustomEvent<string>) => {
          globalThis.__promptSubmitValue = event.detail;
        }) as EventListener);
    });

    const textarea = page.locator('ix-chat-input').locator('textarea');
    await textarea.focus();
    await textarea.press('Enter');

    expect(await page.evaluate(() => globalThis.__promptSubmitValue)).toBe(
      undefined
    );
  }
);

As per coding guidelines, "Prioritize correctness, regressions, accessibility, release impact, and missing validation."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/chat-input/chat-input.tsx` around lines 415 -
429, Add a regression test that verifies ix-chat-input in the "processing" state
ignores Enter: create a test named like "ix-chat-input does not emit
promptSubmit on Enter while processing" that mounts '<ix-chat-input
state="processing" value="..."></ix-chat-input>', attaches a listener to the
promptSubmit event (storing event.detail on globalThis for inspection), focuses
the textarea, simulates pressing Enter, and asserts that the stored global value
remains undefined; this ensures the behavior guarded by handleKeyDown (which
checks this.state === 'processing' and calls submitPrompt only when appropriate)
does not regress.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/core/src/components/chat-input/chat-input.tsx`:
- Around line 415-429: Add a regression test that verifies ix-chat-input in the
"processing" state ignores Enter: create a test named like "ix-chat-input does
not emit promptSubmit on Enter while processing" that mounts '<ix-chat-input
state="processing" value="..."></ix-chat-input>', attaches a listener to the
promptSubmit event (storing event.detail on globalThis for inspection), focuses
the textarea, simulates pressing Enter, and asserts that the stored global value
remains undefined; this ensures the behavior guarded by handleKeyDown (which
checks this.state === 'processing' and calls submitPrompt only when appropriate)
does not regress.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 921832be-336a-4547-9aa1-5aa574f6d61d

📥 Commits

Reviewing files that changed from the base of the PR and between 9f0270f and 4f34ee4.

⛔ Files ignored due to path filters (2)
  • testing/visual-testing/__screenshots__/tests/chat/chat.e2e.ts/chat-overview-1-chromium---classic-dark-linux.png is excluded by !**/*.png
  • testing/visual-testing/__screenshots__/tests/chat/chat.e2e.ts/chat-overview-1-chromium---classic-light-linux.png is excluded by !**/*.png
📒 Files selected for processing (1)
  • packages/core/src/components/chat-input/chat-input.tsx

nuke-ellington
nuke-ellington previously approved these changes Jun 11, 2026
@sonarqubecloud

Copy link
Copy Markdown

@danielleroux danielleroux modified the milestones: 5.1.0, 5.2.0 Jun 22, 2026
nuke-ellington
nuke-ellington previously approved these changes Jul 14, 2026
nuke-ellington
nuke-ellington previously approved these changes Jul 16, 2026
@sonarqubecloud

sonarqubecloud Bot commented Jul 16, 2026 •

Copy link
Copy Markdown

Quality Gate Passed Quality Gate passed

Issues
21 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarQube Cloud

@danielleroux
danielleroux merged commit 70e1c5c into main Jul 21, 2026
74 of 79 checks passed
@danielleroux
danielleroux deleted the feat/chat-components branch July 21, 2026 08:35
@github-actions github-actions Bot mentioned this pull request Jul 21, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Jul 21, 2026
2 of 9 tasks
SaiYugandhar03 pushed a commit to SaiYugandhar03/ix that referenced this pull request Jul 29, 2026
SaiYugandhar03 pushed a commit to SaiYugandhar03/ix that referenced this pull request Aug 3, 2026
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.

2 participants