v2.0.1
Migration guide: v1 -> v2
Version 2 simplifies the configuration API and makes the package ESM-only.
1. Package is ESM-only
CommonJS and UMD builds are no longer published.
Before:
const { bmc } = require('@rhapsodic/bem-classnames');After:
import { bmc } from '@rhapsodic/bem-classnames';If your project still uses CommonJS, migrate the consuming code to ESM or use
dynamic import:
const { bmc } = await import('@rhapsodic/bem-classnames');2. booleanModifier was renamed to flag
The old helper was removed.
Before:
import { bmc, booleanModifier } from '@rhapsodic/bem-classnames';
const classNames = bmc('button', {
modifiers: {
isActive: booleanModifier('state', 'active'),
},
});After:
import { bmc, flag } from '@rhapsodic/bem-classnames';
const classNames = bmc('button', {
modifiers: {
isActive: flag('state', 'active'),
},
});3. stringModifier was renamed to variant
The old helper was removed.
Before:
import { bmc, stringModifier } from '@rhapsodic/bem-classnames';
const classNames = bmc('button', {
modifiers: {
variant: stringModifier('theme', {
primary: 'brand',
secondary: 'neutral',
}),
},
});After:
import { bmc, variant } from '@rhapsodic/bem-classnames';
const classNames = bmc('button', {
modifiers: {
variant: variant('theme', {
primary: 'brand',
secondary: 'neutral',
}),
},
});4. customModifiers was removed
Custom modifiers now live in the same modifiers object as regular prop
modifiers.
Before:
import { bmc, booleanModifier } from '@rhapsodic/bem-classnames';
interface ButtonProps {
size: 'small' | 'large';
}
const classNames = bmc<ButtonProps>('button', {
modifiers: {
size: 'size',
},
customModifiers: {
isLoading: booleanModifier('state', 'loading'),
},
});
classNames({
size: 'large',
isLoading: true,
});After:
import { bmc, flag } from '@rhapsodic/bem-classnames';
interface ButtonProps {
size: 'small' | 'large';
}
const classNames = bmc<ButtonProps, { isLoading: boolean }>('button', {
modifiers: {
size: 'size',
isLoading: flag('state', 'loading'),
},
});
classNames({
size: 'large',
isLoading: true,
});5. New direct shorthand syntax
You can now pass modifiers directly as the second bmc argument.
import { bmc, flag, variant } from '@rhapsodic/bem-classnames';
const classNames = bmc('button', {
size: true,
isActive: flag('state', 'active'),
tone: variant('theme', {
brand: 'primary',
}),
});
classNames({
size: 'large',
isActive: true,
tone: 'brand',
});
// ['button', 'button_size_large', 'button_state_active', 'button_theme_primary']Direct shorthand automatically behaves like whitelist: true, so unrelated
props are not converted into classes.
6. whitelist: true
whitelist can now be true. In that mode, only keys configured in
modifiers are used.
const classNames = bmc('button', {
modifiers: {
size: true,
isActive: flag('state', 'active'),
},
whitelist: true,
});This is equivalent to the direct shorthand:
const classNames = bmc('button', {
size: true,
isActive: flag('state', 'active'),
});7. Reserved keys in direct shorthand
In direct shorthand, modifiers and whitelist are treated as settings keys.
If your props are named modifiers or whitelist, use the explicit settings
syntax.
const classNames = bmc('button', {
modifiers: {
modifiers: true,
whitelist: true,
},
whitelist: true,
});8. Type changes
Some legacy exported types related to the old string/custom modifier API were
removed. Prefer the current public types:
import type {
BooleanModifierSettings,
StringModifierSettings,
ModifiersSettings,
BmcSettings,
PropsWhitelist,
} from '@trenlok/bem-modifier-classes';Quick checklist
- Replace
require(...)with ESMimport. - Replace
booleanModifier(...)withflag(...). - Replace
stringModifier(...)withvariant(...). - Move
customModifiersentries intomodifiers. - Add the second generic to
bmc<TProps, TCustom>()when using custom
modifiers. - Use direct shorthand for new code when possible.