Skip to content

refactor(toggle): migrate Toggle from Flow to TypeScript - #4764

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

refactor(toggle): migrate Toggle from Flow to TypeScript#4764
bonchevskyi wants to merge 1 commit into
box:masterfrom
bonchevskyi:refactor/flow-to-ts-toggle

Conversation

@bonchevskyi

@bonchevskyi bonchevskyi commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Convert Toggle component to TypeScript

This PR converts src/components/toggle from JavaScript with Flow to TypeScript.

Changes

  • Converted Toggle.js to Toggle.tsx with exported ToggleProps interface
  • Converted ToggleField.js to ToggleField.tsx with exported ToggleFieldProps interface
  • Converted index.js to index.ts, re-exporting the components and their types
  • Converted Toggle.stories.js to Toggle.stories.tsx
  • Converted __tests__/Toggle.test.js and __tests__/ToggleField.test.js to .test.tsx
  • Created .js.flow files for backward compatibility

Testing

  • Ran tests for src/components/toggle; all 10 pass with snapshots matching previous output
  • yarn lint:ts and flow check pass

Summary by CodeRabbit

  • New Features

    • Added a configurable toggle switch with labels, descriptions, alignment options, disabled state, accessibility attributes, event callbacks, and ref support.
    • Added Formik integration for using toggles as form fields.
    • Exposed toggle components and their prop types for convenient reuse.
  • Tests

    • Updated toggle and form-field tests for TypeScript compatibility and improved component setup.

@bonchevskyi
bonchevskyi requested a review from a team as a code owner August 10, 2026 14:10
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 54472e49-c6c6-4fff-9588-8d55b6fb15c5

📥 Commits

Reviewing files that changed from the base of the PR and between c6e3fbb and 2c9ff5b.

📒 Files selected for processing (2)
  • src/components/toggle/ToggleField.js.flow
  • src/components/toggle/ToggleField.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/toggle/ToggleField.js.flow
  • src/components/toggle/ToggleField.tsx

Walkthrough

The PR adds TypeScript and Flow-compatible Toggle and ToggleField components. It defines public prop types, controlled checkbox behavior, alignment handling, Formik integration, barrel exports, and TypeScript-compatible test helpers.

Changes

Toggle migration

Layer / File(s) Summary
Toggle component contract and rendering
src/components/toggle/Toggle.tsx, src/components/toggle/Toggle.js.flow
Adds public toggle prop types and renders a controlled checkbox with labels, descriptions, alignment, event handlers, targeting attributes, accessibility semantics, and forwarded refs.
Formik field integration
src/components/toggle/ToggleField.tsx, src/components/toggle/ToggleField.js.flow
Adds Formik wrappers that convert field.value to isOn and forward field and toggle properties.
Public exports and test migration
src/components/toggle/index.ts, src/components/toggle/index.js.flow, src/components/toggle/__tests__/*, src/components/toggle/Toggle.stories.tsx
Adds component and prop-type exports, updates test helpers for TypeScript, and removes the obsolete Flow directive from stories.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: ready-to-merge

Suggested reviewers: vitali-usik

Poem

I toggled the types with a flick of my ear,
Flow stayed beside them, steady and clear.
Formik follows each checkbox’s glow,
While exports hop neatly wherever they go.
Tests nibble the edges, then spring with delight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the migration of the Toggle component from Flow to TypeScript.
Description check ✅ Passed The description explains the migration scope, lists the main changes, and reports relevant test and validation results.
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

🧹 Nitpick comments (1)
src/components/toggle/__tests__/Toggle.test.tsx (1)

8-9: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use typed props in both migrated test helpers.

Both helpers use any, so TypeScript does not validate the public component contracts.

  • src/components/toggle/__tests__/Toggle.test.tsx#L8-L9: use Partial<ToggleProps>.
  • src/components/toggle/__tests__/ToggleField.test.tsx#L7-L8: use a fixture type based on ToggleFieldProps that requires field.
🤖 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/toggle/__tests__/Toggle.test.tsx` around lines 8 - 9, Replace
the any-typed getWrapper props in
src/components/toggle/__tests__/Toggle.test.tsx lines 8-9 with
Partial<ToggleProps>. In src/components/toggle/__tests__/ToggleField.test.tsx
lines 7-8, type the helper fixture from ToggleFieldProps while requiring the
field property, so both migrated test helpers validate their component
contracts.
🤖 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/toggle/Toggle.js.flow`:
- Around line 29-31: Update the onMouseEnter and onMouseLeave callback
declarations in the Toggle prop types to use SyntheticMouseEvent<HTMLDivElement>
instead of SyntheticInputEvent<HTMLDivElement>, matching the container div
handlers while preserving their existing callback signatures.

In `@src/components/toggle/ToggleField.tsx`:
- Around line 9-16: Remove the Formik meta bag before forwarding props from
ToggleField. In src/components/toggle/ToggleField.tsx lines 9-16, destructure
and discard meta alongside form; apply the same change in
src/components/toggle/ToggleField.js.flow lines 11-13 so both wrappers prevent
meta from reaching TogglePrimitive and the native input.

---

Nitpick comments:
In `@src/components/toggle/__tests__/Toggle.test.tsx`:
- Around line 8-9: Replace the any-typed getWrapper props in
src/components/toggle/__tests__/Toggle.test.tsx lines 8-9 with
Partial<ToggleProps>. In src/components/toggle/__tests__/ToggleField.test.tsx
lines 7-8, type the helper fixture from ToggleFieldProps while requiring the
field property, so both migrated test helpers validate their component
contracts.
🪄 Autofix

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: 2061a3ba-9108-481a-a541-7ede3c409e45

📥 Commits

Reviewing files that changed from the base of the PR and between 84b90a7 and c6e3fbb.

⛔ Files ignored due to path filters (2)
  • src/components/toggle/__tests__/__snapshots__/Toggle.test.tsx.snap is excluded by !**/*.snap
  • src/components/toggle/__tests__/__snapshots__/ToggleField.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (9)
  • src/components/toggle/Toggle.js.flow
  • src/components/toggle/Toggle.stories.tsx
  • src/components/toggle/Toggle.tsx
  • src/components/toggle/ToggleField.js.flow
  • src/components/toggle/ToggleField.tsx
  • src/components/toggle/__tests__/Toggle.test.tsx
  • src/components/toggle/__tests__/ToggleField.test.tsx
  • src/components/toggle/index.js.flow
  • src/components/toggle/index.ts
💤 Files with no reviewable changes (1)
  • src/components/toggle/Toggle.stories.tsx

Comment thread src/components/toggle/ToggleField.tsx

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/components/toggle/__tests__/Toggle.test.tsx (1)

8-9: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use typed props in both migrated test helpers.

Both helpers use any, so TypeScript does not validate the public component contracts.

  • src/components/toggle/__tests__/Toggle.test.tsx#L8-L9: use Partial<ToggleProps>.
  • src/components/toggle/__tests__/ToggleField.test.tsx#L7-L8: use a fixture type based on ToggleFieldProps that requires field.
🤖 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/toggle/__tests__/Toggle.test.tsx` around lines 8 - 9, Replace
the any-typed getWrapper props in
src/components/toggle/__tests__/Toggle.test.tsx lines 8-9 with
Partial<ToggleProps>. In src/components/toggle/__tests__/ToggleField.test.tsx
lines 7-8, type the helper fixture from ToggleFieldProps while requiring the
field property, so both migrated test helpers validate their component
contracts.
🤖 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/toggle/Toggle.js.flow`:
- Around line 29-31: Update the onMouseEnter and onMouseLeave callback
declarations in the Toggle prop types to use SyntheticMouseEvent<HTMLDivElement>
instead of SyntheticInputEvent<HTMLDivElement>, matching the container div
handlers while preserving their existing callback signatures.

In `@src/components/toggle/ToggleField.tsx`:
- Around line 9-16: Remove the Formik meta bag before forwarding props from
ToggleField. In src/components/toggle/ToggleField.tsx lines 9-16, destructure
and discard meta alongside form; apply the same change in
src/components/toggle/ToggleField.js.flow lines 11-13 so both wrappers prevent
meta from reaching TogglePrimitive and the native input.

---

Nitpick comments:
In `@src/components/toggle/__tests__/Toggle.test.tsx`:
- Around line 8-9: Replace the any-typed getWrapper props in
src/components/toggle/__tests__/Toggle.test.tsx lines 8-9 with
Partial<ToggleProps>. In src/components/toggle/__tests__/ToggleField.test.tsx
lines 7-8, type the helper fixture from ToggleFieldProps while requiring the
field property, so both migrated test helpers validate their component
contracts.
🪄 Autofix

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: 2061a3ba-9108-481a-a541-7ede3c409e45

📥 Commits

Reviewing files that changed from the base of the PR and between 84b90a7 and c6e3fbb.

⛔ Files ignored due to path filters (2)
  • src/components/toggle/__tests__/__snapshots__/Toggle.test.tsx.snap is excluded by !**/*.snap
  • src/components/toggle/__tests__/__snapshots__/ToggleField.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (9)
  • src/components/toggle/Toggle.js.flow
  • src/components/toggle/Toggle.stories.tsx
  • src/components/toggle/Toggle.tsx
  • src/components/toggle/ToggleField.js.flow
  • src/components/toggle/ToggleField.tsx
  • src/components/toggle/__tests__/Toggle.test.tsx
  • src/components/toggle/__tests__/ToggleField.test.tsx
  • src/components/toggle/index.js.flow
  • src/components/toggle/index.ts
💤 Files with no reviewable changes (1)
  • src/components/toggle/Toggle.stories.tsx
🛑 Comments failed to post (1)
src/components/toggle/Toggle.js.flow (1)

29-31: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect existing Flow mouse-handler type conventions before updating this API.
rg -n -C 2 --glob '*.js.flow' \
  'SyntheticMouseEvent<HTMLDivElement>|onMouseEnter.*Synthetic|onMouseLeave.*Synthetic' \
  src

Repository: box/box-ui-elements

Length of output: 856


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "## Toggle.js.flow"
cat -n src/components/toggle/Toggle.js.flow | sed -n '1,110p'

echo
echo "## Toggle.tsx relevant event props/usages"
if [ -f src/components/toggle/Toggle.tsx ]; then
  cat -n src/components/toggle/Toggle.tsx | sed -n '1,160p'
else
  fd -a 'Toggle.tsx$' .
fi

echo
echo "## Flow event declarations in repo"
rg -n --glob '*.js.flow' --glob 'flow-typed/**' 'SyntheticMouseEvent|SyntheticInputEvent|type SyntheticMouseEvent|type SyntheticInputEvent' site src flow-typed 2>/dev/null | head -200

Repository: box/box-ui-elements

Length of output: 9701


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
for p in Path('.').rglob('*.js.flow'):
    text = p.read_text(errors='ignore')
    if 'SyntheticInputEvent<HTMLDivElement>' in text or 'SyntheticMouseEvent<HTMLDivElement>' in text:
        print(p)
        for i,line in enumerate(text.splitlines(), 1):
            if 'SyntheticInputEvent<HTMLDivElement>' in line or 'SyntheticMouseEvent<HTMLDivElement>' in line:
                print(f'  {i}: {line.strip()}')
PY

Repository: box/box-ui-elements

Length of output: 334


Use mouse event types for the container handlers.

onMouseEnter and onMouseLeave are attached to the toggle container <div> at line 71, so Flow consumers receive mouse events, not input events. Change both declarations to SyntheticMouseEvent<HTMLDivElement>.

🤖 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/toggle/Toggle.js.flow` around lines 29 - 31, Update the
onMouseEnter and onMouseLeave callback declarations in the Toggle prop types to
use SyntheticMouseEvent<HTMLDivElement> instead of
SyntheticInputEvent<HTMLDivElement>, matching the container div handlers while
preserving their existing callback signatures.

@bonchevskyi
bonchevskyi force-pushed the refactor/flow-to-ts-toggle branch from 2c9ff5b to 2748d5e Compare August 12, 2026 11:33
describe('components/toggle/Toggle', () => {
const getWrapper = (props = {}) =>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const getWrapper = (props: any = {}) =>

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.

q: Can we use ToggleProps instead of any here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Tried Partial<ToggleProps> but it blows up on the data-resin-target case, which is there to check rest forwarding. Left any so that test still type-checks.


describe('components/toggle/ToggleField', () => {
const getWrapper = (props = {}) => shallow(<ToggleField {...props} />);
// eslint-disable-next-line @typescript-eslint/no-explicit-any

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.

q: Can we use ToggleFieldProps instead of any here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not really, not without rewriting the fixtures. These tests pass a partial field (onBlur/onChange as strings, no form/meta), which doesn’t satisfy ToggleFieldProps. Same reason the TextInputField tests still use any.

Comment on lines +11 to +13
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- strip Formik form and meta bags from forwarded props
form,
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- strip Formik form and meta bags from forwarded props

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.

q: Should we pass form and meta if we do not use them in component?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We still have to accept them because Formik injects field / form / meta, but we don’t pass form or meta through. They’re pulled off so they don’t end up on Toggle / the input. field is the one we actually spread.

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