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

Proposal for app styles #2

Open
hobbes7878 opened this issue Sep 18, 2018 · 2 comments
Open

Proposal for app styles #2

hobbes7878 opened this issue Sep 18, 2018 · 2 comments

Comments

@hobbes7878
Copy link

Proposal 1

Use CSS modules and colocate SCSS and component files.

card/
  Card.jsx
  card.scss
// Card.jsx
import React from 'react';
import classNames from 'classnames/bind';
import styles from './card.scss';

const cx = classNames.bind(styles);

const Card = props =>
  <div classNames=cx('card', { active: props.active }) />

Proposal 2

Colocate selectors with reducers.

import * as actions from './constants';

// Export reducer as default export
export default (currentState, action) => {
  const initialState = {
    races: {},
  };
  // ...
  return newState;
}

// Export selectors as named exports
export const getActiveRaces = state =>
  state.races.filter(r => r.active);

Selectors should operate on the same state as is defined in the reducer.

Prune the state in another place, if the reducer state is only a piece of the app's store.

import races, * as fromRaces from './races';

export default combineReducers({
  // ...
  races,
});

export const getActiveRaces = (state) =>
  fromRaces.getActiveRaces(state.races);

Proposal 3

Separate files structure by domain instead of by function.

Separated by function.

actions/
  api/
    races.js
  cards.js
  index.js
  nav.js
components/
  Card.jsx
  Nav.jsx
constants/
  actions.js
containers/
  CardWell.jsx
  NavWell.jsx
reducers/
  cards.js
  index.js
  nav.js
stores/
  index.js
App.jsx

Separated by domain.


card/
  actions.js
  Card.jsx
  constants.js
  reducer.js
  Well.jsx
nav/
  actions.js
  constants.js
  Nav.jsx
  reducer.js
  Well.jsx
races/
  actions.js
  api.js
  constants.js
  reducer.js
stores/
  index.js
App.jsx

Proposal 4

Each directory should define all exports in a single file, index.js and all other modules should only consume the exports defined in that file.

card/
  actions.js
  Card.jsx
  constants.js
  index.js
  reducer.js
  Well.jsx
// index.js
export * as actions from './actions';
export * as constants from './constants';
export default as Card from './Card';
// some-other.js
// NOT THIS
import * as cardConstants from '../card/constants';
import * as cardActions from '../card/actions';
import Card from '../card/Card';
// THIS
import { constants as cardConstants, actions as cardActions, Card } from '../card';
@brizandrew
Copy link
Contributor

brizandrew commented Sep 18, 2018

Potential Solve For CSS Inheritance

In order to enable targeted css based on a state that exists above it in terms of inheritance I propose the following composer:

// ./ClassComposer.jsx
import React from 'react';

import classNames from 'classnames';
import omit from 'lodash/omit';

const ClassComposer = (Component, props, styles) => {
  const ClassComposer = class extends React.Component {
    render () {
      const newProps = omit(this.props, [
        'className',
      ]);

      const className = classNames(this.props.className, this.props.inheritedClasses);

      return (
        <Component className={className} {...newProps} />
      );
    }
  };

  return ClassComposer;
};

export default ClassComposer;

Example

This is how it would be used in practice. At the highest level you have a component with a boolean in state that can be toggled. For this example we'll call the component Parent and the boolean mySpecialClassName. We can then use that state to compose a className list using classnames and pass it down to a child along with a component-specific className (in this case child). It looks something like this:

// ./Parent.jsx
import React from 'react';
import classNames from 'classnames';

import Child from './Child/Component';

class Parent extends React.Component {
  constructor (props) {
    super(props);

    this.state = {
      mySpecialClassName: true,
    };
  }

  render () {
    const inheritableClases = classNames({
      mySpecialClassName: this.state.mySpecialClassName,
    });

    const className = classNames('parent', inheritableClases);

    return (
      <div className={className}>
        <p>Paragraph 1.</p>
        <Child inheritedClasses={inheritableClases} className='child' />
      </div>
    );
  }
}

export default Parent;

The child component will then inherit the entire chain as it's className propr which you can use to add more classes to a chain (in this case alongTheWay), and continue passing that along to a grand child.

// ./Child/Component.jsx
import React from 'react';
import classNames from 'classnames';

import ClassComposer from '../ClassComposer';
import GrandChild from './GrandChild/Component';

const BaseChild = (props) => {
  const newPassableClasses = 'alongTheWay';

  const className = classNames(props.className, newPassableClasses);
  const inheritableClases = classNames(props.inheritedClasses, newPassableClasses);

  return (
    <div className={className}>
      <p>Paragraph 2.</p>
      <GrandChild inheritedClasses={inheritableClases} className='grand-child' />
    </div>

  );
};

const Child = ClassComposer(
  BaseChild,
  (props) => props
);

export default Child;

Finally, the grand child component will have all the inherited classes from the Parent and Child components, but not the component-specific classes.

// ./Child/GrandChild/Component.jsx
import React from 'react';

import ClassComposer from '../../ClassComposer';

const BaseGrandChild = (props) => {
  return (
    <p className={props.className}>Paragraph 3.</p>
  );
};

const GrandChild = ClassComposer(
  BaseGrandChild,
  (props) => props
);

export default GrandChild;

When mySpecialClassName is toggled on in the Parent state, the output will look like the following:

<div class="parent mySpecialClassName">
  <p>Paragraph 1.</p>
  <div class="child mySpecialClassName alongTheWay">
    <p>Paragraph 2.</p>
    <p class="grand-child mySpecialClassName alongTheWay">Paragraph 3.</p>
  </div>
</div>

Once the boolean is toggled off, the output will look like the following:

<div class="parent">
  <p>Paragraph 1.</p>
  <div class="child alongTheWay">
    <p>Paragraph 2.</p>
    <p class="grand-child alongTheWay">Paragraph 3.</p>
  </div>
</div>

@brizandrew
Copy link
Contributor

You can see a demo of that proposal here.

https://github.com/The-Politico/demo-css-inheritance

You could probably make an argument that it should be its own npm module so we don't have to copy and paste this file into a utils folder every time we start a new project.

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