Skip to content

[BpkChatbotInput]Bpk component chatbox input#4279

Open
GC Zhu (gc-skyscanner) wants to merge 21 commits intomainfrom
bpk-component-chatbox-input
Open

[BpkChatbotInput]Bpk component chatbox input#4279
GC Zhu (gc-skyscanner) wants to merge 21 commits intomainfrom
bpk-component-chatbox-input

Conversation

@gc-skyscanner
Copy link
Contributor

Remember to include the following changes:

  • Ensure the PR title includes the name of the component you are changing so it's clear in the release notes for consumers of the changes in the version e.g [Clover-123][BpkButton] Updating the colour
  • README.md (If you have created a new component)
  • Component README.md
  • Tests
  • Accessibility tests
    • The following checks were performed:
      • Ability to navigate using a keyboard only
      • Zoom functionality (Deque University explanation):
        • The page SHOULD be functional AND readable when only the text is magnified to 200% of its initial size
        • Pages must reflow as zoom increases up to 400% so that content continues to be presented in only one column i.e. Content MUST NOT require scrolling in two directions (both vertically and horizontally)
      • Ability to navigate using a screen reader only
  • Storybook examples created/updated
  • For breaking changes or deprecating components/properties, migration guides added to the description of the PR. If the guide has large changes, consider creating a new Markdown page inside the component's docs folder and link it here

GC Zhu (gc-skyscanner) and others added 14 commits March 9, 2026 18:29
…operty (#4265)

* add Claude SDD spec for BpkButton

* add notes for the definition of themeable

* Make corner radius configurable via bpk-themeable

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update specs/001-bpkbutton-baseline/spec.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* solve comment

* [CLOV-1327] Address Copilot review comments

- Fix Object.keys → Object.values in BpkButton-test.tsx forEach loop so
  tests iterate over kebab-case type values (e.g. primary-on-dark) that
  match actual BEM class names, not camelCase keys
- Remove unused ButtonType import (no longer needed after removing cast)
- Update plan.md: replace "snapshot regeneration" with accurate description
  of explicit assertion approach; expand Files changed list to include test,
  snapshot deletion, and spec documentation artefacts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* remove the BpkButton spec

* add storybook example for the themed boder radius for BpkButton

* imporve BpkButton unit test

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Bumps the artifacts-actions group with 1 update: [actions/download-artifact](https://github.com/actions/download-artifact).


Updates `actions/download-artifact` from 7.0.0 to 8.0.0
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](actions/download-artifact@37930b1...70fc10c)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: 8.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: artifacts-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 13, 2026 08:52
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new bpk-component-chatbot-input package to Backpack, providing a chat-style input with a default single-line mode and a composer (textarea) mode, plus supporting hooks, styling, tests, and Storybook examples.

Changes:

  • Introduces BpkChatbotInput with default + composer modes and a send button/loading state.
  • Adds supporting hooks (useChatbotInput, useChatbotInputManager, useTextAreaAutoResize, useInputHandlers) and component subparts (InputField, TextAreaField, SendButton).
  • Adds unit tests, accessibility tests, snapshots, and Storybook examples for the new component.

Reviewed changes

Copilot reviewed 31 out of 31 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
packages/bpk-component-chatbot-input/src/types.ts Defines shared prop types for input field variants.
packages/bpk-component-chatbot-input/src/hooks/useTextAreaAutoResize.ts Implements textarea measurement + auto-resize logic.
packages/bpk-component-chatbot-input/src/hooks/useTextAreaAutoResize-test.tsx Tests textarea auto-resize behavior and scrolling behavior.
packages/bpk-component-chatbot-input/src/hooks/useInputHandlers.ts Centralizes click/touch/change handlers for input controls.
packages/bpk-component-chatbot-input/src/hooks/useInputHandlers-test.tsx Tests handler behavior for click/touch/change.
packages/bpk-component-chatbot-input/src/hooks/useChatbotInputManager.ts Adds state management for chatbot input value and submit/autoclear behavior.
packages/bpk-component-chatbot-input/src/hooks/useChatbotInputManager-test.tsx Tests input manager state transitions and submission logic.
packages/bpk-component-chatbot-input/src/hooks/useChatbotInput.ts Provides UI state (focused/disabled/overlimit/etc) and input props for the component.
packages/bpk-component-chatbot-input/src/hooks/useChatbotInput-test.tsx Tests derived state and key-handling behavior for the hook.
packages/bpk-component-chatbot-input/src/hooks/index.ts Barrel exports for hooks used by the component.
packages/bpk-component-chatbot-input/src/constants.ts Declares input type constants and default max character limit.
packages/bpk-component-chatbot-input/src/accessibility-test.tsx Adds jest-axe coverage for default/composer/loading renders.
packages/bpk-component-chatbot-input/src/snapshots/BpkChatbotInput-test.tsx.snap Stores render snapshots for default and composer variants.
packages/bpk-component-chatbot-input/src/TextAreaField/TextAreaField.tsx Implements the composer textarea UI.
packages/bpk-component-chatbot-input/src/TextAreaField/TextAreaField.module.scss Styles for composer textarea container/field.
packages/bpk-component-chatbot-input/src/TextAreaField/TextAreaField-test.tsx Tests textarea field rendering, events, and axe checks.
packages/bpk-component-chatbot-input/src/SendButton/SendButton.tsx Adds send button with icon + loading state behavior.
packages/bpk-component-chatbot-input/src/SendButton/SendButton-test.tsx Tests send button render/click/disabled + axe.
packages/bpk-component-chatbot-input/src/LoadingButton/LoadingButton.tsx Adds a loading button implementation (currently not referenced).
packages/bpk-component-chatbot-input/src/LoadingButton/LoadingButton.module.scss Styles for the loading button.
packages/bpk-component-chatbot-input/src/InputField/InputField.tsx Implements default single-line input UI.
packages/bpk-component-chatbot-input/src/InputField/InputField.module.scss Styles for the single-line input field.
packages/bpk-component-chatbot-input/src/InputField/InputField-test.tsx Tests input field rendering, events, and axe checks.
packages/bpk-component-chatbot-input/src/BpkChatbotInput.tsx Main component wiring modes, hooks, and send button.
packages/bpk-component-chatbot-input/src/BpkChatbotInput.module.scss Styles for default/composer container variants.
packages/bpk-component-chatbot-input/src/BpkChatbotInput-test.tsx Component tests for variants, loading, and keyboard interactions.
packages/bpk-component-chatbot-input/index.ts Public entrypoint exports for the new package.
packages/bpk-component-chatbot-input/README.md Package documentation and usage instructions.
examples/bpk-component-chatbot-input/stories.tsx Storybook story registration for the new component.
examples/bpk-component-chatbot-input/examples.tsx Interactive examples for default/composer/loading states.
examples/bpk-component-chatbot-input/examples.module.scss Example layout styling.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +35 to +41
export const LINE_HEIGHT = 24;
export const MIN_INPUT_HEIGHT = LINE_HEIGHT;
export const MAX_INPUT_HEIGHT_PHASE_1 = LINE_HEIGHT * 4;
export const MAX_INPUT_HEIGHT_PHASE_2 = LINE_HEIGHT * 5;
export const MIN_CONTAINER_HEIGHT = 24;
export const MAX_CONTAINER_HEIGHT = 96;
export const PARENT_PADDING_TOP = 16;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@skyscanner-backpack-bot
Copy link

Visit https://backpack.github.io/storybook-prs/4279 to see this build running in a browser.

@skyscanner-backpack-bot
Copy link

skyscanner-backpack-bot bot commented Mar 13, 2026

Browser support

If this is a visual change, make sure you've tested it in multiple browsers.

Generated by 🚫 dangerJS against 8af6c18

@skyscanner-backpack-bot
Copy link

Visit https://backpack.github.io/storybook-prs/4279 to see this build running in a browser.

@skyscanner-backpack-bot
Copy link

Visit https://backpack.github.io/storybook-prs/4279 to see this build running in a browser.

@skyscanner-backpack-bot
Copy link

Visit https://backpack.github.io/storybook-prs/4279 to see this build running in a browser.

@skyscanner-backpack-bot
Copy link

Visit https://backpack.github.io/storybook-prs/4279 to see this build running in a browser.

Comment on lines +53 to +56
const measureElementRef = useRef<HTMLTextAreaElement | null>(null);
const previousValueRef = useRef<string>('');
const shouldScrollRef = useRef<boolean>(false);
const isInitialRenderRef = useRef<boolean>(true);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why useRef for all four?(same implementation with carhire's)
All four values share one thing in common: changes to them don't need to trigger a UI re-render.

ref reason
measureElementRef Stores a DOM node — the classic use case for useRef
previousValueRef A pure computation helper, only read/written inside effects, never affects render output
shouldScrollRef A cross-effect signal flag — using useState would cause unnecessary re-renders or even an infinite loop
isInitialRenderRef A one-time flag that flips once over the component's lifetime, has no impact on any UI

Of the values in this hook, only dimensions uses useState — because those values are applied directly as inline styles and must trigger a re-render to take effect visually.


const textarea = ref.current;
const computedStyle = getComputedStyle(textarea);
const tempTextarea = document.createElement('textarea');
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason why use tempTextArea here(Same implemetation with Car hire's)
The real textarea is for display — its height is locked. The hidden textarea is for measurement — its height is free to expand. By mirroring the same content and styles in the hidden element, we can measure the true height the content needs, then apply that height back to the real textarea.

@skyscanner-backpack-bot
Copy link

Visit https://backpack.github.io/storybook-prs/4279 to see this build running in a browser.

document.body.appendChild(tempTextarea);
measureElementRef.current = tempTextarea;

const resizeObserver = new ResizeObserver((entries) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Add ResizeObserver here(different from carhire, the original implementation)
Reason is:
The height calculation fails when the container width changes
previously recalculates the height only when the value changes ⬇️


However, measureEl.style.width depends on textarea.offsetWidth. If the user does not input any new content but only the width of the container changes due to window scaling or layout alterations, the width will remain the old value and the calculation of the number of lines will be incorrect.

for example:
The user entered three lines of text, and the window narrowed → it actually became five lines
But value remains unchanged → Effect 2 is not triggered → height is still displayed in 3 lines ❌

RichardSyq

This comment was marked as off-topic.

@skyscanner-backpack-bot
Copy link

Visit https://backpack.github.io/storybook-prs/4279 to see this build running in a browser.

@skyscanner-backpack-bot
Copy link

Visit https://backpack.github.io/storybook-prs/4279 to see this build running in a browser.

width: 100%;
align-items: center;
transition:
height 0.3s cubic-bezier(0.4, 0, 0.2, 1),
Copy link
Contributor Author

@gc-skyscanner GC Zhu (gc-skyscanner) Mar 17, 2026

Choose a reason for hiding this comment

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

No match backpack token at the moment, Keep it same as Car Hire's
Image

transition:
border-color tokens.$bpk-duration-sm ease,
box-shadow tokens.$bpk-duration-sm ease;
border: 1.5 * tokens.$bpk-one-pixel-rem solid tokens.$bpk-line-day;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

No match backpack token at the moment, keep it same as Car Hire's

Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai: claude minor Non breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants