maximkoretskiy / postcss-autoreset

PostCSS plugin for automatic rules isolation
MIT License
244 stars 11 forks source link

Common styles in reusable components reseted by non-common styles, passed from outside #14

Closed alex35mil closed 7 years ago

alex35mil commented 8 years ago

Can't figure out how to handle the case w/ reusable component (which contains common styles for component) + non-common styles, passed to component as a className via props. The issue is that css className, passed to reusable component, reset the internal styles of this component, eg:

/* some/DeleteButton.css */

.button {
  background-color: red;
}
/* some/DeleteButton.jsx */

import React from 'react';

import Button from 'reusable/Button.jsx';
import styles from './DeleteButton.css';

export default (props) => (
  <Button {...props} className={styles.button} />
);
/* reusable/Button.css */

/* should be applied to all buttons in the app */
.button {
  cursor: pointer;
  ...
}
/* reusable/Button.jsx */

import React from 'react';
import classNames from 'classnames'

import styles from './Button.css';

export default ({ className, ...otherProps }) => (
  <button
    {...otherProps}
    className={classNames(
      styles.button, // <- this will be reseted by reset of the `className`
      className,     // <- only these styles will be applied
    )}
  />
);

The only solution I can think of is to remove reusable styles from reusable components and replace them w/ mixins/custom properties, which must be applied to every button in the app, but it seems more as a workaround, rather than solution.

alex35mil commented 8 years ago

One more workaround is to !important all properties in reusable css, eg:

/* reusable/Button.css */

/* should be applied to all buttons in the app */
.button {
  cursor: pointer !important;
  ...
}

But can't call it a solution as well.

UPDATE: Well, yeah, totally unusable, since you can't @apply --my-custom-property; here.

ai commented 8 years ago

postcss-autoreset was created for component philosophy. In component philosophy, you couldn’t override .button in delete-button.css.

Why you need it? Let’s find better solution.

alex35mil commented 8 years ago

you couldn’t override .button in delete-button.css Why you need it?

@ai Here are my common cases for buttons:

/* delete-button.css */
.button {
  margin-right: 10px; /* add extra margin from content on the right */
}

.button {
  min-width: 120px; /* apply minimum width */
}

Here I can wrap the Button in additional div and make button width: 100%/flex: 1, but it's additional div.

One more case, that I can think of, is:

.processing {
  color: transparent; /* to show spinner over the button */
}
<div className={styles.positionRelative}>
  <Button {...props} className={{ [styles.processing]: isProcessing }}>
    Save
  </Button>
  {isProcessing && <Spinner />}
</div>

Here tho I can make text transparent via Button's api instead of passing className since it's common.

export default ({ textHidden }) => (
  <button className={classNames(styles.button, { [styles.textHidden]: textHidden })} />
);

But anyway there's not only reusable buttons in the app and reusables might be used in different contexts, so explicitly applying context-specific styles to common components might be justified.

P.S. In the response in twitter by "alter architecture" you meant to use rulesMatcher function to ignore classname, that's being passed to common component?

ai commented 8 years ago

@alexfedoseev sorry, I still can’t understood you :) maybe we should talk in Russia in chat: https://gitter.im/ai

maximkoretskiy commented 7 years ago

@ai @alexfedoseev Have you solved this problem?

alex35mil commented 7 years ago

@maximkoretskiy Kinda. AFAIU the only way to apply style variation to component is to implement api for this variation. Other stylings (eg margins, positioning) must be applied via external wrapper (div).