Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[QUESTION] Handling different component 'types' #4

Open
shiro opened this issue Sep 5, 2018 · 1 comment
Open

[QUESTION] Handling different component 'types' #4

shiro opened this issue Sep 5, 2018 · 1 comment

Comments

@shiro
Copy link
Contributor

shiro commented Sep 5, 2018

Thanks for the great work on the project.
I was wondering if there is a good way to handle components which look differently depending on a prop.
example:

export interface IProps{
    type?: 'primary' | 'secondary'; // optional, defaults to default style
}

My approach:

case 1: component has a container element of sorts

// Button.tsx
const Button: React.SFC<IProps> = (props) => {
    const theme = getThemeFromProps(style, props);
    if(styles[props.type])
        theme.container = styles[props.type];

    return (
        <div className={theme.container}>
            <Child theme={theme} themePrefix="Child-" />
        </div>
    );
}
// Button.scss
.container{
    & > .Child-element{ ... }
}
.primary{
    @extend .container;

    // primary styles
    .container > .Child-element{ ... }
}
...

The approach is not pretty at all IMO. It shouldn't be solved with @extend, also readability 😭.

case 2: component does not have a container element

// Button.tsx
const Button: React.SFC<IProps> = (props) => {
    const theme = getThemeFromProps(style, props);

    return (
        <Child>
            <a>Example use case.</a>
        </Child>
    );
}

No idea how to solve this as .A > .B cannot be used (we do not want to add extra wrapper divs, it could result in unexpected layout changes we'd then have to fix with css, also DOM bloat).

Why I think making type wrappers is bad
In my opinion creating wrapper components for every type is not practical, also it's merely a visual rather than semantic difference.

Imagine we have more than 10 type variants per component and we are working with a big code-base.
The project will be a bloated mess in no time.

@klimashkin
Copy link
Owner

klimashkin commented Sep 5, 2018

Not sure that I've got your question correctly, but if you have a Button with different types, the easiest way to style it would be something like that. Assume your default type is standard, primary and secondary are optionals.

.button {
  position: relative;
  display: inline-flex;
  justify-content: center;
  align-content: center;
  align-items: center;
  font: inherit;
  line-height: 1.25;
  cursor: pointer;
  user-select: none;
  border: none;
}

.standard {
  composes: button;
  background-color: gray;
}

.primary {
  composes: button;
  background-color: green;
}

.secondary {
  composes: button;
  background-color: blue;
}

...
import PropTypes from 'prop-types';
import {PureComponent} from 'react';
import {mixThemeWithProps} from '@css-modules-theme/react';
import styles from './Button.css';

export default class Button extends PureComponent {
  static propTypes = {
    // The html style of the button
    style: PropTypes.oneOf(['standard', 'primary', 'secondary']),
  };

  static defaultProps = {
    style: 'standard',
  }

  render() {
    // Use mixThemeWithProps to pass all the rest props directly to dom
    const {style, theme, ...buttonProps} = mixThemeWithProps(styles, this.props);
   
    // Don't need to concatenate `.button` classname with classname for style type, 
    // because they already concatenated statically using `compose` in css.
    buttonProps.className = theme[style];

    return <button {...buttonProps}>;
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants