React library of Swarm Design System components
Switch branches/tags
Clone or download
hsbacot Merge pull request #652 from meetup/MG-3117_dropdown_hover_styling_re…
…moved_on_mouse_leave

adding state to track if user is on keyboard to control hover & focus…
Latest commit c2ad5c2 Oct 22, 2018
Permalink
Failed to load latest commit information.
.github Adding yarn install after post merge/pull + minor template tweak (#161) Apr 7, 2017
.storybook reorder addons storybook Oct 2, 2018
.travis update deploy keys Apr 11, 2017
__mocks__ add text content mocks Jun 4, 2018
assets adding state to track if user is on keyboard to control hover & focus… Oct 12, 2018
flow-typed Merge pull request #654 from meetup/MG-2974_add_knobs_layout_components Oct 16, 2018
src Merge pull request #652 from meetup/MG-3117_dropdown_hover_styling_re… Oct 22, 2018
util update import paths, raf polyfill for tests Oct 24, 2017
.babelrc Merge branch 'master' of github.com:meetup/meetup-web-components into… Jul 20, 2018
.editorconfig update editorconfig with max line length matching `mup-web` settings Dec 21, 2017
.eslintignore flow plugins, config, libdefs Jun 14, 2018
.eslintrc.airbnb.js rm webpack resolver section from airbnb eslintrc Nov 13, 2017
.eslintrc.js full LocalDate support with flowtype Jun 14, 2018
.flowconfig flowing + clearing field when value is zero Jul 17, 2018
.gitignore adding vs code configs to gitignore Sep 27, 2018
.npmignore update deploy keys Apr 11, 2017
.prettierignore configure prettier for scss and js May 31, 2018
.prettierrc configure prettier for scss and js May 31, 2018
.stylelintignore resolve stylelint errors May 30, 2018
.stylelintrc upgrade swarm-sasstools Jul 6, 2018
.travis.yml UXCapture for Meetup log in Nav (#638) Oct 2, 2018
.yarnrc flow plugins, config, libdefs Jun 14, 2018
CHANGELOG.md deprecating Sep 28, 2018
Makefile deprecating Sep 28, 2018
README.md updated command for updating mwc version Sep 5, 2018
jest.config.json fixed AppBadge tests Feb 21, 2018
package.json Merge pull request #654 from meetup/MG-2974_add_knobs_layout_components Oct 16, 2018
yarn.lock Merge pull request #654 from meetup/MG-2974_add_knobs_layout_components Oct 16, 2018

README.md

npm version Build Status Coverage Status

meetup-web-components

Meetup library of React UI components for the web.

Table of Contents

Component checklist

This checklist can be used as a guide for adding components that are easy to reuse and maintain. The categories come from a talk I saw Elyse Holladay give at Clarity Conf 2017.

Easy to reason about

  • It will be clear to other designers or engineers what problem the component solves and when to use it
  • All properties, options and variants are documented in Storybook
  • Has unit tests
  • Provides logical defaults
  • If there can be errors, error states are designed and documented
  • If the component has become complex, it has been broken into smaller components

Context-agnostic

  • Doesn't rely on a parent component to behave or look correctly
  • Doesn't have logic that controls functionality outside of itself e.g.: if there is a button in the component, it should take an event handler via props instead of assuming what the button is going to do
  • Works in supported browsers and devices
  • Design is accessible for all users
  • Provides necessary ARIA information
  • Design won't cause issues with translation or internationalization

Independent and isolated

  • Only affects itself
  • Defines itself and its styles only in one place
  • Ready to use "out of the box" in consumer apps or by other components

Releases

This package uses semver versioning to tag releases, although the patch version is determined exclusively by the Travis build number for pushes to master. Major and minor versions are hard-coded into the Makefile.

Manual pushes to master and PR merges to master will be built by Travis, and will kick off the yarn publish routine. The currently-published version of the package is shown on the repo homepage on GitHub in a badge at the top of the README.

Development/Beta releases

When developing a consumer application that requires changes to the platform code, you can release a beta version of the platform on npm by opening a PR in the meetup-web-platform repo. When it builds successfully, a new beta version will be added to the list of available npm versions. The generated version number is in the Travis build logs, which you can navigate to by clicking on 'Show all checks' in the box that says 'All checks have passed', and then getting the 'Details' of the Travis build.

screen shot 2016-10-29 at 10 25 20 am

screen shot 2016-10-29 at 10 25 29 am

At the bottom of the build log, there is a line that echos the GIT_TAG. If you click the disclosure arrow, the version number will be displayed, e.g. 0.5.177-beta.

screen shot 2016-10-29 at 10 25 59 am

screen shot 2016-10-29 at 10 26 06 am

You can then install this beta version into your consumer application with

> yarn add meetup-web-components@<version tag>

Each time you push a change to your meetup-web-components PR, you'll need to re-install it with the new tag in your consumer application code.

The overall workflow is:

  1. Open a PR for your meetup-web-components branch
  2. Wait for Travis to successfully build your branch (this can take 5+ minutes)
  3. Get the version string from the build logs under GIT_TAG
  4. (if needed) Push changes to your meetup-web-components branch
  5. Repeat steps 2-3

Getting started

You can generate the boilerplate files for React components using yarn run generate, which invokes src/utils/generate.js.

The command will prompt you for a 'type' (select from the list of options), and a 'name'. It generates the following files in src/ :

  • <ComponentName>.jsx Component JSX module
  • <componentName>.test.jsx Component test script
  • <componentName>.story.jsx Storybook script

Components

Located in the src/ directory, component files live alongside their corresponding .test and .story files.

Filename casing conventions:

  • Component files: CamelCase, with a leading capital, i.e. RsvpTag.jsx
  • Test files: camelCase, i.e. rsvpTag.test.js
  • Story files: camelCase, i.e. rsvpTag.story.jsx

Redux Form Components

We use redux-form in our mup-web app to help with validation flow.

redux-form can use our form components (just pass our MWC component to Field as the component prop), but we need to write wrappers to pass down the props from redux-form Field to our form components in meetup-web-components.

The job of the wrapper for each component is mostly just parsing out the meta, input and other props from redux-form and passing them on.

Conventions

You can find the wrapper classes in src/forms/redux-form.

The files are named after the classes they wrap to avoid verbose file names. Ex. forms/TogglePill.jsx has a forms/redux-form/TogglePill.jsx.

But the actual class name to import and displayName, have ReduxForm in the name.
Ex. export class ReduxFormTogglePill

We write wrappers as we need them, so if you don't find one that you need, please write it!

Gotchas

We've run into a couple gotchas already: redux-form validates all fields on load, and its hard to tell when the form is first rendered. To avoid displaying errors right away, we added some logic to read meta.touched. https://github.com/meetup/meetup-web-components/pull/307

redux-form's implementation of checkboxes give them values of true and false. ReduxFormTogglePill wrappers handle this now by passing the input.value prop down as isActive (which sets checked on checkboxes) https://github.com/meetup/meetup-web-components/pull/310.
We may need to do this for other checkbox, radio component wrappers.

Layout conventions

The src/ directory contains layout helpers, like Section and Chunk. These are documented in Storybook, but a more detailed guide can be found here.

Testing

Unit testing UI components is a little weird compared with unit testing business logic.

  1. You have to decide what aspects of a UI element are intrinsic to its appearance rather than just implementation details
  2. UI elements evolve based on aesthetic tastes as much as functional requirements - inflexible tests require a lot of maintenance
  3. Headless testing of browser-dependent objects requires some extra tooling to simulate the target environment

Simulating interaction

TestUtils.Simulate appears to work correctly for our testing setup - it should be used for all tests that involve simulating events, like onClick. Check out button.test.js for an example.

Verifying child elements

In UI testing, there is an almost invisible line between testing the implementation (markup) and testing the behavior (appearance/content), and ideally you only should test the behavior - there are loads of ways to change markup without changing the fundamental app experience, and those kinds of markup changes should not be considered "bugs" that result in failed tests.

The implication for constructing unit tests is that you should avoid relying on the specific markup (tags and DOM structure). Sometimes it's unavoidable, but if you are inclined to use getElementsByTagName, firstChild/lastChild, or a querySelector(All) that includes a tag name to access particular parts of the component UI, check whether there is a better way to skip over the markup implementation details and grab what you want explicitly.

A useful option is to add a PCV className to the element of interest, and just use yourComponentEl.querySelector('.specificClassName') to find it. Classnames are free and DOM-independent, which means that no matter what the markup is for your event name, you can always unit-test the behavior (text content) accurately with

// good
expect(eventNode.querySelector('.event-name').textContent).toEqual(testEventName);

// bad - assumes both tag (h5) and structure (first h5 in the card)
expect(eventNode.getElementsByTagName('h5')[0].textContent).toEqual(testEventName);

Linting

To manually lint your code, run:

$ yarn run lint

Whitespace issues will be fixed automatically - just remember to commit the changes. Other style issues will log errors. Our .eslintrc configuration is based on the 'recommended' preset, with a number of additional rules that have been requested by the dev team. It's a 'living' standard, however, so please feel free to send PRs with updates!

Storybook

Before building any components, it's helpful to know what related components have already been built into our Foundation library. We use React Storybook to display components outside of the app context. To open it, run:

$ yarn install
$ yarn run storybook

And open the viewer at http://localhost:9001

All of the available components are listed on the left, and clicking on one will open it in the preview pane. Variants are also listed in the left column to show how different states affect the rendered component.