Skip to content

Conversation

@luarmr
Copy link
Contributor

@luarmr luarmr commented Nov 13, 2025

refactor(bem): complete BEM migration - remove remaining BemWithSpecificContext usage

Summary

Completes the Label Studio BEM migration by migrating 7 additional files that used BemWithSpecificContext() pattern, which were not included in PR #8765.

Total migrated: 7 files
Pattern: const { Block, Elem } = BemWithSpecificContext()
Result: 100% BEM migration complete for Label Studio

Background

PR #8765 migrated 24 files that used direct Block/Elem imports. This PR covers the remaining files that used the BemWithSpecificContext() pattern - a different import style that creates isolated BEM contexts.

Changes

Migration Pattern

Before:

import { BemWithSpecificContext } from "../../utils/bem";

const { Block, Elem } = BemWithSpecificContext();

<Block name="component" mod={{ variant }}>
  <Elem name="item">{children}</Elem>
</Block>

After:

import { cn } from "../../utils/bem";

<div className={cn("component").mod({ variant }).toClassName()}>
  <div className={cn("component").elem("item").toClassName()}>{children}</div>
</div>

Files Migrated

Components (6 files):

  1. Space.jsx - Layout spacing component
  2. RadioGroup.jsx - Form radio input group
  3. Breadcrumbs.jsx - Navigation breadcrumbs with dropdown support
  4. Menu.jsx - Main menu with Spacer, Divider, Group subcomponents
  5. InviteLink.tsx - Organization invite modal
  6. ExportPage.jsx - Data export modal with format selection

Cleanup (1 file):
7. MenuContext.js - Removed unused Block/Elem exports

Verification

<Block> JSX usage: 0
✅ <Elem> JSX usage: 0
✅ Block/Elem imports: 0
✅ BemWithSpecificContext usage: 0
✅ bem.tsx exports: Only cn()
✅ Files using cn(): 51

bem.tsx (final):

export { cnb as cn } from "@humansignal/core/lib/utils/bem";

Safety Analysis

Why these migrations are safe:

  1. BemWithSpecificContext creates isolated contexts
    Each call creates a separate Block/Elem instance - children cannot inherit context from parents in different files.

  2. No cross-repository dependencies
    LSE has its own copies of these components (Space, Menu, etc.) and doesn't import from LSO.

  3. Internal children migrated together
    Components like RadioGroup.Button and Menu.Spacer are defined in the same file and migrated simultaneously.

  4. No external Block/Elem children
    Verified that no external code passes <Block> or <Elem> as children to these components.

Statistics

Commits: 7

  • 6 component migrations
  • 1 cleanup (MenuContext)

Lines changed: 67 insertions, 84 deletions
Files modified: 9

Combined with PR #8765:

Migrated Space component from BemWithSpecificContext() to cn() helper.
- Replaced BemWithSpecificContext import with cn import
- Removed const { Block } = BemWithSpecificContext() pattern
- Converted Block name="space-ls" with mod and mix to div with cn().mod().mix()
- Preserved all props, mods (direction, size, spread, stretch, align), and children
- No behavior change, equivalent class strings

Part of Label Studio BEM migration (Additional files)
Migrated RadioGroup and RadioButton components from BemWithSpecificContext() to cn() helper.
- Replaced BemWithSpecificContext import with cn import
- Removed const { Block, Elem } = BemWithSpecificContext() pattern
- Converted Block name="radio-group-ls" with mod and mix to div with cn().mod().mix()
- Converted Elem name="buttons" to div with cn().elem()
- Converted Elem name="button" in RadioButton to div with cn().elem().mod()
- Preserved all props, refs, context, handlers, and form integration
- No behavior change, equivalent class strings

Part of Label Studio BEM migration (Additional files)
Migrated Breadcrumbs component from BemWithSpecificContext() to cn() helper.
- Replaced BemWithSpecificContext import with cn import
- Removed const { Block, Elem } = BemWithSpecificContext() pattern
- Converted Block name="breadcrumbs" to div with cn("breadcrumbs")
- Converted Elem tag="ul" name="list" to ul with cn().elem()
- Converted Elem tag="span" name="label" to span with cn().elem().mod()
- Converted all Elem tag="li" name="item" variations to li with cn().elem().mod()
- Converted Elem with component={Dropdown.Trigger} to Dropdown.Trigger with component="li"
- Preserved all props, handlers, dropdown integration, and conditional rendering
- No behavior change, equivalent class strings

Part of Label Studio BEM migration (Additional files)
Migrated ExportPage and FormatInfo components from BemWithSpecificContext() to cn() helper.
- Replaced BemWithSpecificContext import with cn import
- Removed const { Block, Elem } = BemWithSpecificContext() pattern
- Converted Block name="export-page" to div with cn("export-page")
- Converted Block name="formats" to div with cn("formats")
- Converted all Elem components (footer, recent, actions, info, list, item, name, tag, description, feedback)
- Preserved all props, handlers, modal integration, and format selection logic
- No behavior change, equivalent class strings

Part of Label Studio BEM migration (Additional files - FINAL!)
@netlify
Copy link

netlify bot commented Nov 13, 2025

Deploy Preview for label-studio-docs-new-theme canceled.

Name Link
🔨 Latest commit d633545
🔍 Latest deploy log https://app.netlify.com/projects/label-studio-docs-new-theme/deploys/69155c7272e7a00008cb17fb

@netlify
Copy link

netlify bot commented Nov 13, 2025

Deploy Preview for heartex-docs canceled.

Name Link
🔨 Latest commit d633545
🔍 Latest deploy log https://app.netlify.com/projects/heartex-docs/deploys/69155c726777f300099723a1

@netlify
Copy link

netlify bot commented Nov 13, 2025

Deploy Preview for label-studio-storybook ready!

Name Link
🔨 Latest commit d633545
🔍 Latest deploy log https://app.netlify.com/projects/label-studio-storybook/deploys/69155c724dc18900086c4d11
😎 Deploy Preview https://deploy-preview-8814--label-studio-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

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

@luarmr luarmr requested review from a team and yyassi-heartex November 13, 2025 04:00
@netlify
Copy link

netlify bot commented Nov 13, 2025

Deploy Preview for label-studio-playground ready!

Name Link
🔨 Latest commit d633545
🔍 Latest deploy log https://app.netlify.com/projects/label-studio-playground/deploys/69155c72cd8c160008c94cf0
😎 Deploy Preview https://deploy-preview-8814--label-studio-playground.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

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

Migrated InviteLink InvitationModal from Block to cn() helper.
- Replaced Block import from MenuContext with cn import
- Converted Block name="invite" to div with cn("invite")
- Preserved all props and Input integration
- No behavior change, equivalent class strings

Part of Label Studio BEM migration (Additional files)
Migrated Menu, Menu.Spacer, Menu.Divider, and Menu.Group from Block/Elem to cn() helper.
- Removed Block/Elem imports from MenuContext
- Converted Block tag="ul" name="main-menu" with mod and mix to ul with cn().mod().mix()
- Converted Menu.Spacer Elem to li with cn("main-menu").elem("spacer")
- Converted Menu.Divider Elem to li with cn("main-menu").elem("divider")
- Converted Menu.Group Block and Elems to div/ul structure with cn()
- Preserved all props, refs, handlers, context, and dropdown integration
- No behavior change, equivalent class strings

Part of Label Studio BEM migration (Additional files)
Cleaned up MenuContext to remove unused Block/Elem exports.
- Removed BemWithSpecificContext import
- Removed Block/Elem exports (no longer used after Menu.jsx migration)
- Only MenuContext remains (still needed for menu state)
- No behavior change

Part of Label Studio BEM migration (Additional files)
@codecov
Copy link

codecov bot commented Nov 13, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 59.68%. Comparing base (3fa83e0) to head (d633545).
⚠️ Report is 6 commits behind head on develop.

❗ There is a different number of reports uploaded between BASE (3fa83e0) and HEAD (d633545). Click for more details.

HEAD has 1 upload less than BASE
Flag BASE (3fa83e0) HEAD (d633545)
pytests 1 0
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #8814      +/-   ##
===========================================
- Coverage    67.70%   59.68%   -8.03%     
===========================================
  Files          806      553     -253     
  Lines        62093    38986   -23107     
  Branches     10328    10328              
===========================================
- Hits         42043    23268   -18775     
+ Misses       20047    15715    -4332     
  Partials         3        3              
Flag Coverage Δ
lsf-e2e 53.51% <ø> (-0.81%) ⬇️
lsf-integration 50.68% <ø> (+<0.01%) ⬆️
lsf-unit 8.35% <ø> (ø)
pytests ?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@luarmr luarmr requested a review from bmartel November 13, 2025 04:05
import { Button, Typography } from "@humansignal/ui";
import { Space } from "@humansignal/ui/lib/space/space";
import { Block } from "apps/labelstudio/src/components/Menu/MenuContext";
import { cn } from "apps/labelstudio/src/utils/bem";
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Brandon probably can help here to decide If this is correct or should drive from @HumanSignal

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants