refactor(pill-cloud): migrate PillCloud from Flow to TypeScript - #4723
refactor(pill-cloud): migrate PillCloud from Flow to TypeScript#4723bonchevskyi wants to merge 1 commit into
Conversation
WalkthroughAdds the ChangesPillCloud component
Estimated code review effort: 2 (Simple) | ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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
⛔ Files ignored due to path filters (1)
src/components/pill-cloud/__tests__/__snapshots__/PillCloud.test.tsx.snapis excluded by!**/*.snap
📒 Files selected for processing (7)
src/components/index.tssrc/components/pill-cloud/PillCloud.js.flowsrc/components/pill-cloud/PillCloud.stories.tsxsrc/components/pill-cloud/PillCloud.tsxsrc/components/pill-cloud/__tests__/PillCloud.test.tsxsrc/components/pill-cloud/index.js.flowsrc/components/pill-cloud/index.ts
| 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; |
There was a problem hiding this comment.
🎯 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 || trueRepository: 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 }));
JSRepository: 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
doneRepository: 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.
| 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} |
There was a problem hiding this comment.
🎯 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: mergebuttonProps.classNameandbuttonProps.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.
Convert PillCloud component to TypeScript
This PR converts
src/components/pill-cloudfrom JavaScript with Flow to TypeScript.Changes
PillCloud.jstoPillCloud.tsxwith exportedPillCloudPropsinterfacePillCloudOptioninterface, replacing the Flow-onlyOptiontype imported frompill-selector-dropdown/flowTypesindex.jstoindex.ts, re-exporting the component and its typesPillCloud.stories.jstoPillCloud.stories.tsx__tests__/PillCloud.test.jstoPillCloud.test.tsx.js.flowfiles for backward compatibilityPillCloudexports tosrc/components/index.tsTesting
src/components/pill-cloud; all 7 pass with the regenerated snapshot matching the previous outputyarn lint:tsandflow checkpassComponents/PillCloud) that pill selection behavior is unchangedSummary by CodeRabbit