Skip to content

refactor(pill-cloud): migrate PillCloud from Flow to TypeScript - #4723

Open
bonchevskyi wants to merge 1 commit into
box:masterfrom
bonchevskyi:refactor/flow-to-ts-pill-cloud
Open

refactor(pill-cloud): migrate PillCloud from Flow to TypeScript#4723
bonchevskyi wants to merge 1 commit into
box:masterfrom
bonchevskyi:refactor/flow-to-ts-pill-cloud

Conversation

@bonchevskyi

@bonchevskyi bonchevskyi commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Convert PillCloud component to TypeScript

This PR converts src/components/pill-cloud from JavaScript with Flow to TypeScript.

Changes

  • Converted PillCloud.js to PillCloud.tsx with exported PillCloudProps interface
  • Added exported PillCloudOption interface, replacing the Flow-only Option type imported from pill-selector-dropdown/flowTypes
  • Converted index.js to index.ts, re-exporting the component and its types
  • Converted PillCloud.stories.js to PillCloud.stories.tsx
  • Converted __tests__/PillCloud.test.js to PillCloud.test.tsx
  • Created .js.flow files for backward compatibility
  • Added PillCloud exports to src/components/index.ts

Testing

  • Ran tests for src/components/pill-cloud; all 7 pass with the regenerated snapshot matching the previous output
  • yarn lint:ts and flow check pass
  • Manually verified in Storybook (Components/PillCloud) that pill selection behavior is unchanged

Summary by CodeRabbit

  • New Features
    • Added a reusable pill-style selection component that displays configurable options as buttons.
    • Supports selected-state highlighting, click handling, and customizable button properties.
    • Exposed the component and its associated option and property types for use throughout the application.
  • Tests
    • Updated component tests and examples to cover selected-pill behavior and typed option data.

@bonchevskyi
bonchevskyi requested a review from a team as a code owner July 25, 2026 15:41
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds the PillCloud component with typed options, selection handling, button prop forwarding, Flow and TypeScript exports, and updated story and test typing.

Changes

PillCloud component

Layer / File(s) Summary
PillCloud contract, rendering, and exports
src/components/pill-cloud/PillCloud.tsx, src/components/pill-cloud/PillCloud.js.flow, src/components/pill-cloud/index.ts, src/components/pill-cloud/index.js.flow, src/components/index.ts
Defines public option and prop types, renders selectable buttons, forwards button props, and exposes the component through module and barrel exports.
Story typing and selection assertions
src/components/pill-cloud/PillCloud.stories.tsx, src/components/pill-cloud/__tests__/PillCloud.test.tsx
Types story options and state with PillCloudOption and simplifies selected-pill assertions.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

I’m a bunny hopping through the cloud,
Where pill buttons bloom in a colorful crowd.
Selected ones sparkle, clicks softly take flight,
Typed little options keep everything right.
Export the bundle—thump, thump, goodnight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately summarizes the main change: migrating PillCloud from Flow to TypeScript.
Description check ✅ Passed The description covers the main changes and testing, and no required repository-specific sections are missing from the template.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 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 `@src/components/pill-cloud/PillCloud.tsx`:
- Around line 27-37: Protect internally controlled props in both PillCloud
implementations: update PillCloud in src/components/pill-cloud/PillCloud.tsx
(lines 27-37) and src/components/pill-cloud/PillCloud.js.flow (lines 16-27) so
buttonProps cannot replace the generated pill classes, onSelect behavior, or
resin target. Merge buttonProps.className with the generated className, merge
its onClick with the internal selection callback, and place buttonProps before
the generated props so data-resin-target remains controlled.
- Around line 8-13: Update PillCloudOption and the PillCloud rendering logic so
each option uses a guaranteed unique, non-null identifier for both the React key
and data-resin-target instead of nullable, potentially duplicated value. Prefer
making the existing id required and enforcing uniqueness, or validate and reject
invalid duplicate/null identifiers; add regression tests covering duplicate and
null values.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7069b18c-8b79-4e1a-8467-f0179ff9ef80

📥 Commits

Reviewing files that changed from the base of the PR and between dce056d and ba52acc.

⛔ Files ignored due to path filters (1)
  • src/components/pill-cloud/__tests__/__snapshots__/PillCloud.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (7)
  • src/components/index.ts
  • src/components/pill-cloud/PillCloud.js.flow
  • src/components/pill-cloud/PillCloud.stories.tsx
  • src/components/pill-cloud/PillCloud.tsx
  • src/components/pill-cloud/__tests__/PillCloud.test.tsx
  • src/components/pill-cloud/index.js.flow
  • src/components/pill-cloud/index.ts

Comment on lines +8 to +13
export interface PillCloudOption {
/** Text shown on the pill */
displayText: string;
id?: string;
/** Value used as the pill key and resin target */
value: string | number | null;

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Files matching PillCloud:"
fd -i 'PillCloud' . || true

echo
echo "Relevant source:"
if [ -f src/components/pill-cloud/PillCloud.tsx ]; then
  wc -l src/components/pill-cloud/PillCloud.tsx
  cat -n src/components/pill-cloud/PillCloud.tsx
fi

echo
echo "Search PillCloudOption usage:"
rg -n "PillCloudOption|usePill|data-resin-target|\\.value" src || true

Repository: box/box-ui-elements

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "PillCloud tests:"
if [ -f src/components/pill-cloud/__tests__/PillCloud.test.tsx ]; then
  wc -l src/components/pill-cloud/__tests__/PillCloud.test.tsx
  cat -n src/components/pill-cloud/__tests__/PillCloud.test.tsx
fi

echo
echo "Story options:"
if [ -f src/components/pill-cloud/PillCloud.stories.tsx ]; then
  cat -n src/components/pill-cloud/PillCloud.stories.tsx
fi

echo
echo "React key/null behavior probe:"
node - <<'JS'
const reactKey = String(null);
const dataResinTarget = null;
console.log(JSON.stringify({ reactKey, dataResinTarget, type: typeof dataResinTarget }));
JS

Repository: box/box-ui-elements

Length of output: 5776


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Button component:"
for f in src/components/button/Button.tsx src/components/button/Button.js.flow; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    wc -l "$f"
    cat -n "$f"
  fi
done

Repository: box/box-ui-elements

Length of output: 8614


Use a stable, unique option key for PillCloud.

option.value is nullable and not required to be unique, but it is used as both the React key and data-resin-target at lines 31 and 36. Duplicate values can destabilize React reconciliation, and id is optional; prefer a guaranteed unique non-null key or validate this contract, including regression tests for duplicate/null values.

🤖 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 `@src/components/pill-cloud/PillCloud.tsx` around lines 8 - 13, Update
PillCloudOption and the PillCloud rendering logic so each option uses a
guaranteed unique, non-null identifier for both the React key and
data-resin-target instead of nullable, potentially duplicated value. Prefer
making the existing id required and enforcing uniqueness, or validate and reject
invalid duplicate/null identifiers; add regression tests covering duplicate and
null values.

Comment on lines +27 to +37
const PillCloud = ({ options, onSelect, selectedOptions = [], buttonProps = {} }: PillCloudProps) => (
<div className="bdl-PillCloud pill-cloud-container">
{options?.map(option => (
<Button
key={option.value}
className={classNames('bdl-Pill', 'bdl-PillCloud-button', 'pill', 'pill-cloud-button', {
'is-selected': selectedOptions.find(op => isEqual(op, option)),
})}
onClick={onSelect ? () => onSelect(option) : undefined}
data-resin-target={option.value}
{...buttonProps}

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Protect internally controlled PillCloud props in both implementations.

Both implementations spread buttonProps after generated props, allowing callers to remove required pill classes or bypass onSelect. Merge custom class names and callbacks while preserving the component’s internal behavior.

  • src/components/pill-cloud/PillCloud.tsx#L27-L37: merge buttonProps.className and buttonProps.onClick, then keep the generated resin target.
  • src/components/pill-cloud/PillCloud.js.flow#L16-L27: apply the same prop ordering and callback-merging behavior.
📍 Affects 2 files
  • src/components/pill-cloud/PillCloud.tsx#L27-L37 (this comment)
  • src/components/pill-cloud/PillCloud.js.flow#L16-L27
🤖 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 `@src/components/pill-cloud/PillCloud.tsx` around lines 27 - 37, Protect
internally controlled props in both PillCloud implementations: update PillCloud
in src/components/pill-cloud/PillCloud.tsx (lines 27-37) and
src/components/pill-cloud/PillCloud.js.flow (lines 16-27) so buttonProps cannot
replace the generated pill classes, onSelect behavior, or resin target. Merge
buttonProps.className with the generated className, merge its onClick with the
internal selection callback, and place buttonProps before the generated props so
data-resin-target remains controlled.

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