Convert 7 components to BEM class naming convention
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
315
app/RSpade/upstream_changes/bem_class_naming_12_19.txt
Executable file
315
app/RSpade/upstream_changes/bem_class_naming_12_19.txt
Executable file
@@ -0,0 +1,315 @@
|
||||
BEM CLASS NAMING - MIGRATION GUIDE
|
||||
Date: 2024-12-19
|
||||
|
||||
SUMMARY
|
||||
RSX components should use BEM (Block Element Modifier) naming convention for
|
||||
CSS class names. This ensures that HTML class names match the compiled SCSS
|
||||
selectors and that styles apply correctly.
|
||||
|
||||
The key insight: SCSS nested selectors like `.Component_Name { &__element {} }`
|
||||
compile to `.Component_Name__element`. If HTML uses a different class name
|
||||
(like `component-name__element` or `component__element`), the styles won't
|
||||
apply. This migration standardizes all component child class names to use
|
||||
the exact PascalCase component prefix.
|
||||
|
||||
A code quality rule (JQHTML-CLASS-01) now detects BEM naming violations at
|
||||
manifest-time, providing immediate feedback when HTML classes don't match
|
||||
the expected SCSS-compiled selectors.
|
||||
|
||||
DESIGN PRINCIPLES
|
||||
|
||||
1. BEM Naming Convention
|
||||
Block: Component_Name (the component's root class, auto-added by jqhtml)
|
||||
Element: Component_Name__element-name (child elements, double underscore)
|
||||
Modifier: Component_Name--modifier-name (state variations, double hyphen)
|
||||
|
||||
2. PascalCase Component Prefix
|
||||
Components use PascalCase with underscores (e.g., My_Component). BEM child
|
||||
classes MUST use the exact same prefix, NOT kebab-case or lowercase.
|
||||
|
||||
CORRECT: My_Component__header, My_Component__item-list
|
||||
WRONG: my-component__header, my_component__header
|
||||
|
||||
3. SCSS Nesting Compiles to BEM
|
||||
SCSS:
|
||||
.My_Component {
|
||||
&__header { color: blue; }
|
||||
&__item { padding: 10px; }
|
||||
&--active { background: green; }
|
||||
}
|
||||
|
||||
Compiles to:
|
||||
.My_Component__header { color: blue; }
|
||||
.My_Component__item { padding: 10px; }
|
||||
.My_Component--active { background: green; }
|
||||
|
||||
HTML must use these exact class names for styles to apply.
|
||||
|
||||
AFFECTED FILES
|
||||
|
||||
Any component with child element classes that use:
|
||||
- kebab-case prefix (e.g., my-component__element)
|
||||
- lowercase prefix (e.g., my_component__element)
|
||||
- generic class names (e.g., .header, .item, .content)
|
||||
|
||||
Framework components already migrated:
|
||||
rsx/theme/components/navigation/sidebar/sidebar_nav.*
|
||||
rsx/theme/components/datagrid/datagrid_abstract.*
|
||||
rsx/theme/components/datagrid/datagrid_body.*
|
||||
rsx/theme/components/feedback/errors/php_exception_error_page_component.*
|
||||
rsx/theme/components/feedback/errors/generic_error_page_component.*
|
||||
rsx/theme/components/forms/pin_verification_form.*
|
||||
rsx/theme/components/page/breadcrumb_nav.*
|
||||
rsx/app/frontend/Frontend_Spa_Layout.*
|
||||
rsx/app/frontend/frontend_spa_layout.scss
|
||||
|
||||
IDENTIFYING CANDIDATES FOR CONVERSION
|
||||
|
||||
Step 1: Search for generic class names in SCSS files
|
||||
-------------------------------------------------------------------------
|
||||
Look for SCSS files with nested class selectors that don't use &__ syntax:
|
||||
|
||||
grep -rn "^\s*\." rsx/app rsx/theme/components --include="*.scss" | \
|
||||
grep -v "&__" | grep -v "&--" | grep -v "^\s*\.\$"
|
||||
|
||||
Common patterns to look for:
|
||||
- .component-name .child-element { } (nested selector, not BEM)
|
||||
- .my-component__element { } (kebab-case prefix instead of PascalCase)
|
||||
- .generic-class-name { } (standalone classes that should be scoped)
|
||||
|
||||
Step 2: Find SCSS files with potential BEM candidates
|
||||
-------------------------------------------------------------------------
|
||||
Search for hyphenated class names that suggest component children:
|
||||
|
||||
grep -rE "\.[a-z]+-[a-z]+" rsx/app rsx/theme/components --include="*.scss" | \
|
||||
grep -v "bootstrap" | grep -v "bi-" | grep -v "btn-" | grep -v "form-"
|
||||
|
||||
This finds classes like:
|
||||
- .sidebar-brand, .nav-link, .page-content
|
||||
- .error-icon, .loading-row, .empty-state
|
||||
|
||||
Step 3: Check corresponding jqhtml templates
|
||||
-------------------------------------------------------------------------
|
||||
For each SCSS file with candidates, check the matching jqhtml file:
|
||||
|
||||
# Example: if datagrid_abstract.scss has candidates
|
||||
cat rsx/theme/components/datagrid/datagrid_abstract.jqhtml | \
|
||||
grep -oE 'class="[^"]*"'
|
||||
|
||||
Step 4: Verify the component structure
|
||||
-------------------------------------------------------------------------
|
||||
A good candidate for BEM conversion has:
|
||||
- A component root class (from <Define:Component_Name>)
|
||||
- Child elements with generic or kebab-case class names
|
||||
- Styles that only make sense within that component's context
|
||||
|
||||
CONVERSION PROCESS
|
||||
|
||||
1. Update SCSS to use BEM nesting
|
||||
-------------------------------------------------------------------------
|
||||
Convert nested selectors to use &__ syntax:
|
||||
|
||||
Before:
|
||||
.My_Component {
|
||||
.header { ... }
|
||||
.item-list { ... }
|
||||
.item { ... }
|
||||
}
|
||||
|
||||
After:
|
||||
.My_Component {
|
||||
&__header { ... }
|
||||
&__item-list { ... }
|
||||
&__item { ... }
|
||||
}
|
||||
|
||||
Or for flat selectors:
|
||||
|
||||
Before:
|
||||
.My_Component {
|
||||
// styles
|
||||
}
|
||||
.my-component__header {
|
||||
// styles
|
||||
}
|
||||
|
||||
After:
|
||||
.My_Component {
|
||||
// styles
|
||||
|
||||
&__header {
|
||||
// styles
|
||||
}
|
||||
}
|
||||
|
||||
2. Update jqhtml template class names
|
||||
-------------------------------------------------------------------------
|
||||
Change class attributes to use the BEM naming:
|
||||
|
||||
Before:
|
||||
<div class="header">...</div>
|
||||
<ul class="item-list">...</ul>
|
||||
<li class="item">...</li>
|
||||
|
||||
After:
|
||||
<div class="My_Component__header">...</div>
|
||||
<ul class="My_Component__item-list">...</ul>
|
||||
<li class="My_Component__item">...</li>
|
||||
|
||||
3. Update JavaScript selectors
|
||||
-------------------------------------------------------------------------
|
||||
If the component has a .js file, update any jQuery selectors:
|
||||
|
||||
Before:
|
||||
that.$.find('.header')
|
||||
that.$.find('.item-list .item')
|
||||
$element.addClass('loading')
|
||||
|
||||
After:
|
||||
that.$.find('.My_Component__header')
|
||||
that.$.find('.My_Component__item-list .My_Component__item')
|
||||
$element.addClass('My_Component--loading')
|
||||
|
||||
4. Update dynamically generated class names
|
||||
-------------------------------------------------------------------------
|
||||
If JavaScript dynamically creates elements with classes:
|
||||
|
||||
Before:
|
||||
$('<a>', { class: 'row-link', href: url })
|
||||
|
||||
After:
|
||||
$('<a>', { class: 'DataGrid_Abstract__row-link', href: url })
|
||||
|
||||
COMMON PATTERNS
|
||||
|
||||
Generic Classes to Convert
|
||||
-------------------------------------------------------------------------
|
||||
These patterns commonly appear and should be converted:
|
||||
|
||||
.icon → Component_Name__icon
|
||||
.header → Component_Name__header
|
||||
.title → Component_Name__title
|
||||
.subtitle → Component_Name__subtitle
|
||||
.content → Component_Name__content
|
||||
.body → Component_Name__body
|
||||
.footer → Component_Name__footer
|
||||
.item → Component_Name__item
|
||||
.list → Component_Name__list
|
||||
.message → Component_Name__message
|
||||
.actions → Component_Name__actions
|
||||
.loading → Component_Name__loading or Component_Name--loading
|
||||
.empty → Component_Name__empty or Component_Name--empty
|
||||
|
||||
State Modifiers (use -- not __)
|
||||
-------------------------------------------------------------------------
|
||||
.active → Component_Name--active
|
||||
.disabled → Component_Name--disabled
|
||||
.loading → Component_Name--loading (if state, not container)
|
||||
.expanded → Component_Name--expanded
|
||||
.collapsed → Component_Name--collapsed
|
||||
.error → Component_Name--error
|
||||
.success → Component_Name--success
|
||||
|
||||
Layout Specific Classes
|
||||
-------------------------------------------------------------------------
|
||||
Layout components like Frontend_Spa_Layout typically have:
|
||||
|
||||
.app-sidebar → Layout_Name__sidebar
|
||||
.app-content → Layout_Name__content
|
||||
.app-header → Layout_Name__header
|
||||
.page-content → Layout_Name__page-content
|
||||
.sidebar-brand → Layout_Name__sidebar-brand
|
||||
|
||||
PRESERVING BOOTSTRAP CLASSES
|
||||
|
||||
Do NOT convert Bootstrap utility or component classes:
|
||||
|
||||
Keep as-is:
|
||||
.btn, .btn-primary, .btn-sm
|
||||
.form-control, .form-label
|
||||
.d-flex, .d-none, .d-lg-block
|
||||
.text-center, .text-muted
|
||||
.mb-3, .py-5, .px-4
|
||||
.card, .card-body, .card-header
|
||||
.dropdown, .dropdown-menu, .dropdown-item
|
||||
.navbar, .navbar-brand
|
||||
.breadcrumb, .breadcrumb-item
|
||||
|
||||
Only convert custom classes that are component-specific.
|
||||
|
||||
CONFIGURATION
|
||||
|
||||
No configuration required.
|
||||
|
||||
The JQHTML-CLASS-01 code quality rule automatically detects:
|
||||
- Component names that don't start with uppercase
|
||||
- Redundant class attributes on Define tags
|
||||
- BEM child classes using kebab-case or lowercase prefix
|
||||
|
||||
VERIFICATION
|
||||
|
||||
1. Run code quality check:
|
||||
php artisan rsx:check
|
||||
|
||||
Any BEM naming violations will be reported with suggestions.
|
||||
|
||||
2. Search for unconverted patterns:
|
||||
grep -rE "class=\"[^\"]*[a-z]+-[a-z]+__" rsx/app rsx/theme --include="*.jqhtml"
|
||||
|
||||
This finds remaining kebab-case__element patterns.
|
||||
|
||||
3. Compile bundles and check for SCSS errors:
|
||||
php artisan rsx:bundle:compile Frontend_Bundle
|
||||
|
||||
4. Visually inspect pages to ensure styles still apply:
|
||||
- Check components render correctly
|
||||
- Verify hover states, active states work
|
||||
- Test responsive behavior
|
||||
|
||||
EXAMPLE MIGRATION
|
||||
|
||||
Complete example: Converting Sidebar_Nav component
|
||||
|
||||
sidebar_nav.scss (before):
|
||||
.Sidebar_Nav {
|
||||
.nav-section { margin-bottom: 24px; }
|
||||
.nav-section-title { font-size: 12px; }
|
||||
.nav-link { padding: 12px 16px; }
|
||||
.nav-submenu { padding-left: 32px; }
|
||||
}
|
||||
|
||||
sidebar_nav.scss (after):
|
||||
.Sidebar_Nav {
|
||||
&__section { margin-bottom: $nav-section-margin; }
|
||||
&__section-title { font-size: $font-size-xs; }
|
||||
&__link { padding: $nav-link-padding; }
|
||||
&__submenu { padding-left: $nav-submenu-indent; }
|
||||
}
|
||||
|
||||
sidebar_nav.jqhtml (before):
|
||||
<div class="nav-section">
|
||||
<div class="nav-section-title"><%= section.title %></div>
|
||||
<a href="..." class="nav-link">...</a>
|
||||
<div class="nav-submenu">...</div>
|
||||
</div>
|
||||
|
||||
sidebar_nav.jqhtml (after):
|
||||
<div class="Sidebar_Nav__section">
|
||||
<div class="Sidebar_Nav__section-title"><%= section.title %></div>
|
||||
<a href="..." class="Sidebar_Nav__link">...</a>
|
||||
<div class="Sidebar_Nav__submenu">...</div>
|
||||
</div>
|
||||
|
||||
sidebar_nav.js (before):
|
||||
that.$.find('.nav-link').on('click', ...)
|
||||
$parent.find('.nav-submenu').slideDown()
|
||||
|
||||
sidebar_nav.js (after):
|
||||
that.$.find('.Sidebar_Nav__link').on('click', ...)
|
||||
$parent.find('.Sidebar_Nav__submenu').slideDown()
|
||||
|
||||
REFERENCE
|
||||
|
||||
rsx/theme/CLAUDE.md - SCSS guidelines including BEM
|
||||
php artisan rsx:man scss - SCSS organization conventions
|
||||
php artisan rsx:man jqhtml - Component template documentation
|
||||
Reference in New Issue
Block a user