bem / bem-react

A set of tools for developing user interfaces using the BEM methodology in React
http://bem.github.io/bem-react
Other
440 stars 64 forks source link

@bem-react/core: proposal for props from withBemMod #381

Open yarastqt opened 5 years ago

yarastqt commented 5 years ago

Проблема

Хочется иметь возможность контролировать свойства которые будут переданы в оборачиваемый компонент из модификатора.

Имеется кейс:

const Button = ({ type = 'button', ...props }) => (
  <button type={type} {...props} />
)

const withTypeLink = withBemMod('Button', { type: 'link' })
const EnhancedButton = withTypeLink(Button)
const renderer = () => <EnhancedButton type="link" />
// Результат -> <button class="Button Button_type_link" type="link" />
// Получаем невалидное HTML свойство type="link"

Хотелось бы, чтобы в обернутый компонент не попадали определенные свойства, которые будут невалидны для HTML размети, можно было бы сделать omit для такого свойства:

const withTypeLink = withBemMod('Button', { type: 'link' }, (WrappedComponent) => (
  ({ type, ...props }) => <WrappedComponent {...props} />
))

Но такой вариант слишком громоздкий, а подобных кейсов очень много.

Предложение

По дефолту удалять те свойства на которые сматчился модификатор, но дать возможность оставлять нужные свойства, передав в качестве второго аргумента массив из предиката и свойств которые нужно оставить (либо сделать наоборот).

Вариант 1

const withTypeLink = withBemMod('Button', { type: 'link' })
// В обернутый компонент не попадет свойство type: link
const withTypeLink = withBemMod('Button', [{ type: 'link' }, 'type' [, ...etc]])
// В обернутый компонент попадет свойство type: link

Вариант 2

const withTypeLink = withBemMod('Button', { type: 'link' })
// В обернутый компонент попадет свойство type: link
const withTypeLink = withBemMod('Button', [{ type: 'link' }, 'type' [, ...etc]])
// В обернутый компонент не попадет свойство type: link

Свойства можно удалять/оставлять только те, что описаны в интерфейсе модификатора.

awinogradov commented 5 years ago

Look at this https://github.com/awinogradov/condicom/blob/master/index.tsx

yarastqt commented 5 years ago

Нашел ещё один кейс, когда возникает такая же проблема:

const Textinput = ({ addonBefore, ...props }: any) => {
  return <input {...props} />
}

const withClear = withBemMod('Textinput', { hasClear: true }, (Wrapped: any) => ({ hasClear, ...props }: any) => (
  <Wrapped {...props} addonBefore={<>X</>} />
))

const TextinputEnhanced = withClear(Textinput)

const App = () => (
  <TextinputEnhanced hasClear={false} />
)

Есть так же базовый компонент который принимает все свойства, и есть опциональный модификатор, который может быть выключен, в итоге мы получаем на DOM узле не валидный атрибут.

Glazomer commented 4 years ago

Нашел ещё один кейс, когда возникает такая же проблема:

const Textinput = ({ addonBefore, ...props }: any) => {
  return <input {...props} />
}

const withClear = withBemMod('Textinput', { hasClear: true }, (Wrapped: any) => ({ hasClear, ...props }: any) => (
  <Wrapped {...props} addonBefore={<>X</>} />
))

const TextinputEnhanced = withClear(Textinput)

const App = () => (
  <TextinputEnhanced hasClear={false} />
)

Есть так же базовый компонент который принимает все свойства, и есть опциональный модификатор, который может быть выключен, в итоге мы получаем на DOM узле не валидный атрибут.

Возпроизвел код: https://codesandbox.io/s/vigilant-surf-bxqnc

Можете объяснить ошибку? Вижу только ошибку в консоли, это и есть она?