diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ecce2dd5fd3..b753be4cb7e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,14 +1,16 @@ # Contribution guidelines + 1. [Roadmap](#roadmap) 2. [Developing Components](#developing-components) * [Tools we use](#tools-we-use) * [Component patterns](#component-patterns) * [Adding default theme](#adding-default-theme) * [Adding system props](#adding-system-props) + * [Adding the sx prop](#adding-the-sx-prop) * [Linting](#linting) * [Testing](#testing) * [TypeScript support](#typescript-support) - * [Additonal resources](#additional-resources) + * [Additional resources](#additional-resources) 3. [Writing documentation](#writing-documentation) 4. [Creating a pull request](#creating-a-pull-request) * [What to expect after opening a pull request](#what-to-expect-after-opening-a-pull-request) @@ -22,8 +24,8 @@ * [System Props](#system-props) ## Roadmap -If you're looking for something to work on, a great place to start is our issues labeled [up for grabs](https://github.com/primer/components/issues?q=is%3Aopen+is%3Aissue+label%3A%22up+for+grabs%22)! If you've got a feature that you'd like to implement, be sure to check out our [Primer Components Roadmap](https://github.com/primer/components/projects/3) to make sure it hasn't already been started on. +If you're looking for something to work on, a great place to start is our issues labeled [up for grabs](https://github.com/primer/components/issues?q=is%3Aopen+is%3Aissue+label%3A%22up+for+grabs%22)! If you've got a feature that you'd like to implement, be sure to check out our [Primer Components Roadmap](https://github.com/primer/components/projects/3) to make sure it hasn't already been started on. ## Developing components @@ -31,7 +33,7 @@ We primarily use our documentation site as a workspace to develop new components To get the documentation site running locally run the following in your terminal: -``` +```sh yarn start ``` @@ -42,27 +44,31 @@ Navigate to http://localhost:8000/ to see the site in your browser ✨ 1. We use [styled-components](https://www.styled-components.com/) to style our components. 2. We use style functions from [styled-system](https://styled-system.com/) whenever possible, and styled-systems' `style()` function to create new ones. - ### Component patterns With a couple of exceptions, all components should be created with the `styled` function from [styled-components] and should have the appropriate groups of system props attached. Default values for system props can be set in `Component.defaultProps`. -Prop Types from system props such as `COMMON` or `TYPOGRAPHY` as well as styled-system functions can be spread in the component's prop types declaration (see example below). +Prop Types from system props such as `COMMON` or `TYPOGRAPHY` as well as styled-system functions can be spread in the component's prop types declaration (see example below). These need to go *after* any built-in styles that you want to be overridable. ⚠️ **Make sure to always set the default `theme` prop to our [theme](https://github.com/primer/components/blob/master/src/theme.js)! This allows consumers of our components to access our theme values without a ThemeProvider.** +Additionally, every component should support [the `sx` prop](https://primer.style/components/overriding-styles); remember to add `${sx}` to the style literal and `...sx.propTypes` to the component's `propTypes`. + Here's an example of a basic component written in the style of Primer Components: ```jsx import {TYPOGRAPHY, COMMON} from './constants' import theme from './theme' +import sx from './sx const Component = styled.div` - ${TYPOGRAPHY}; - ${COMMON}; // additional styles here + + ${COMMON}; + ${TYPOGRAPHY}; + ${sx}; ` Component.defaultProps = { @@ -73,13 +79,15 @@ Component.defaultProps = { Component.propTypes = { ...COMMON.propTypes, - ...TYPOGRAPHY.propTypes + ...TYPOGRAPHY.propTypes, + ...sx.propTypes } export default Component ``` ### Adding default theme + Each component needs access to our default Primer Theme, so that users of the component can access theme values easily in their consuming applications. To add the default theme to a component, import the theme and assign it to the component's defaultProps object: @@ -94,6 +102,7 @@ Component.defaultProps = { ``` ### Adding system props + Each component should have access to the appropriate system props. Every component has access to `COMMON`. For **most** components added, you'll only need to give the component to `COMMON`. If you are unsure, ping a DS team member on your PR. Categories of system props are exported from `src/constants.js`: @@ -101,8 +110,9 @@ Categories of system props are exported from `src/constants.js`: * `COMMON` includes color and spacing (margin and padding) props * `TYPOGRAPHY` includes font family, font weight, and line-height props * `POSITION` includes positioning props -* `FLEX_CONTAINER` includes flexbox props for containers -* `FLEX_ITEM` includes flexbox props for items in a flex container +* `FLEX` includes flexbox props +* `BORDER` includes border and box-shadow props +* `GRID` includes grid props To give the component access to a group of system props, import the system prop function from `./constants` and include the system prop function in your styled-component like so: @@ -110,8 +120,8 @@ To give the component access to a group of system props, import the system prop import {COMMON} from './constants' const Component = styled.div` - ${COMMON}; // additional styles here + ${COMMON}; ` // don't forget to also add it to your prop type declaration! @@ -121,17 +131,42 @@ Component.propTypes = { } ``` +Remember that the system prop function inside your style declaration needs to go *after* any built-in styles you want to be overridable. + +### Adding the `sx` prop + +Each component should provide access to a prop called `sx` that allows for setting theme-aware ad-hoc styles. See the [overriding styles](https://primer.style/components/overriding-styles) doc for more information on using the prop. + +Adding the `sx` prop is similar to adding system props; import the default export from the `sx` module, add it to your style definition, and add the appropriate prop types. **The `sx` prop should go at the *very end* of your style definition.** + +```jsx +import {COMMON} from './constants' +import sx from './sx' + +const Component = styled.div` + // additional styles here + ${COMMON}; + ${sx}; +` + +// don't forget to also add it to your prop type declaration! + +Component.propTypes = { + ...COMMON.propTypes, + ...sx.propTypes +} +``` + ### Linting We use the [React configuration](https://github.com/github/eslint-plugin-github/blob/master/lib/configs/react.js) from [GitHub's eslint plugin](https://github.com/github/eslint-plugin-github) to lint our JavaScript. To check your work before pushing, run: -``` +```sh yarn run lint ``` Or, you can use [npx] to run eslint on one or more specific files: - ```sh # lint the component and the tests in src/__tests__ npx eslint src/**/MyComponent.js @@ -149,7 +184,7 @@ yarn run lint -- --fix We test our components with [Jest](https://facebook.github.io/jest/) and [react-test-renderer](https://reactjs.org/docs/test-renderer.html). You can run the tests locally with `yarn test`. To run the tests as you work, run Jest in watch mode with: -``` +```sh yarn test -- --watch ``` @@ -159,15 +194,15 @@ See [`src/__tests__/example.js`](src/__tests__/example.js) for examples of ways Several of the projects that consume Primer Components are written in TypeScript. Though Primer Components is not currently written in TS, we do export type definitions in order to make Primer Components compatible with other TS projects. -Whenever adding new components or modifying the props of an existing component, **please make sure to update the type definition** in `index.d.ts`! This is super important to make sure we don't break compatibility :) +Whenever adding new components or modifying the props of an existing component, **please make sure to update the type definition** in `index.d.ts`! This is super important to make sure we don't break compatibility :) ### Additional resources -- [Primer Components Philosophy](https://primer.style/components/philosophy) -- [Primer Components Core Concepts](https://primer.style/components/core-concepts) -- [Primer Components System Props](https://primer.style/components/system-props) -- [Styled Components docs](https://styled-components.com/) -- [Styled System docs](https://styled-system.com/) +* [Primer Components Philosophy](https://primer.style/components/philosophy) +* [Primer Components Core Concepts](https://primer.style/components/core-concepts) +* [Primer Components System Props](https://primer.style/components/system-props) +* [Styled Components docs](https://styled-components.com/) +* [Styled System docs](https://styled-system.com/) ## Writing documentation @@ -180,37 +215,41 @@ To add a new component to our documentation site, create a new file with the `.m When creating a new pull request, please follow the guidelines in the auto-populated pull request template. Be sure to add screenshots of any relevant work and a thoughtful description. ### What to expect after opening a pull request -After opening a pull request, a member of the design systems team will add the appropriate labels (major, minor, patch release labels) and update the base branch to the correct release branch. Usually, you'll receive a response from the design systems team within a day or two. The design systems team member will review the pull request keeping the following items in mind: +After opening a pull request, a member of the design systems team will add the appropriate labels (major, minor, patch release labels) and update the base branch to the correct release branch. Usually, you'll receive a response from the design systems team within a day or two. The design systems team member will review the pull request keeping the following items in mind: ### What we look for in reviews -- If it's a new component, does the component make sense to add to Primer Components? (Ideally this is discussed before the pull request stage, please reach out to a DS member if you aren't sure if a component should be added to Primer Componets!) -- Does the component follow our [Primer Components code style](#component-patterns)? -- Does the component use theme values for most CSS values? -- Does the component have access to the [default theme](#adding-default-theme)? -- Does the component have the [correct system props implemented](#adding-system-props)? -- Is the component API intuitive? -- Does the component have the appropriate [type definitions in `index.d.ts`](#typescript-support)? -- Is the component documented accurately? -- Does the component have appropriate tests? -- Does the pull request increase the bundle size significantly? - -If everything looks great, the design systems team member will approve the pull request and merge when appropriate. Minor and patch changes are released frequently, and we try to bundle up breaking changes and avoid shipping major versions too often. If your pull request is time-senstive, please let a design systems team member know. You do not need to worry about merging pull requests on your own, we'll take care of that for you :) + +* If it's a new component, does the component make sense to add to Primer Components? (Ideally this is discussed before the pull request stage, please reach out to a DS member if you aren't sure if a component should be added to Primer Components!) +* Does the component follow our [Primer Components code style](#component-patterns)? +* Does the component use theme values for most CSS values? +* Does the component have access to the [default theme](#adding-default-theme)? +* Does the component have the [correct system props implemented](#adding-system-props)? +* Is the component API intuitive? +* Does the component have the appropriate [type definitions in `index.d.ts`](#typescript-support)? +* Is the component documented accurately? +* Does the component have appropriate tests? +* Does the pull request increase the bundle size significantly? + +If everything looks great, the design systems team member will approve the pull request and merge when appropriate. Minor and patch changes are released frequently, and we try to bundle up breaking changes and avoid shipping major versions too often. If your pull request is time-sensitive, please let a design systems team member know. You do not need to worry about merging pull requests on your own, we'll take care of that for you :) ## Deploying and publishing ### Deploying -All of our documentation sites use the [Now integration](https://github.com/organizations/primer/settings/installations/1007619) to deploy documentation changes whenever code is merged into master. The integration also creates a preview site every time you commit code to a branch. To view the preview site, navigate to the PR and find the comment from the `now` bot. This will include a link to the preview site for your branch. + +All of our documentation sites use the [Now integration](https://github.com/organizations/primer/settings/installations/1007619) to deploy documentation changes whenever code is merged into master. The integration also creates a preview site every time you commit code to a branch. To view the preview site, navigate to the PR and find the comment from the `now` bot. This will include a link to the preview site for your branch. Once you merge your branch into master, any changes to the docs will automatically deploy. No further action is necessary. ### Path aliasing + This site is served as a subdirectory of [primer.style] using a [path alias](https://zeit.co/docs/features/path-aliases) configured in that repo's [`rules.json`](https://github.com/primer/primer.style/tree/master/rules.json). If you change the production deployment URL for this app, you will also need to change it there and re-deploy that app; otherwise, Now will automatically route requests from [primer.style/components](https://primer.style/components/) to the new deployment whenever you alias this one to `primer-components.now.sh`. ### Publishing + We use a custom GitHub Actions to handle all of our processes relating to publishing to NPM. This includes release candidates, canary releases, and publishing the final release. -The [publish GitHub Action](https://github.com/primer/publish) will automatically publish a canary release for each commit to a branch. If the branch is prefixed with `release-` it will publish a release candidate. To find the canary release or release candidtate, navigate to the PR and find the `publish` check in the merge box. Clicking on the `details` link for the check will navigate you to the unpkg page for that canary release/release candidate. For more documentation on our publish GitHub Action and workflows, please refer to the [`@primer/publish` repo](https://github.com/primer/publish). +The [publish GitHub Action](https://github.com/primer/publish) will automatically publish a canary release for each commit to a branch. If the branch is prefixed with `release-` it will publish a release candidate. To find the canary release or release candidate, navigate to the PR and find the `publish` check in the merge box. Clicking on the `details` link for the check will navigate you to the unpkg page for that canary release/release candidate. For more documentation on our publish GitHub Action and workflows, please refer to the [`@primer/publish` repo](https://github.com/primer/publish). ## Troubleshooting @@ -225,6 +264,7 @@ Ensure you are using the latest minor of Node.js for the major version specified ## Glossary ### System props + System props are style functions that provide one or more props, and can be passed directly the return value of [styled-components]'s `styled()` function: ```jsx diff --git a/docs/content/overriding-styles.mdx b/docs/content/overriding-styles.mdx new file mode 100644 index 00000000000..5d227a4c7ff --- /dev/null +++ b/docs/content/overriding-styles.mdx @@ -0,0 +1,73 @@ +--- +title: Overriding styles with the sx prop +--- + +Our goal with Primer Components is to hit the sweet spot between providing too little and too much styling flexibility; too little and the design system is too rigid, and too much and it becomes too difficult to maintain a consistent style. Our components already support a standard set of [system props](/system-props), but sometimes a component just isn't *quite* flexible enough to look the way you need it to look. For those cases, we provide the `sx` prop. + +The `sx` prop allows ad-hoc styling that is still theme aware. Declare the styles you want to apply in camel-cased object notation, and try to use theme values in appropriate CSS properties when possible. If you've passed a custom theme using `ThemeProvider` or a `theme` prop, the `sx` prop will honor the custom theme. For more information on theming in Primer Components, check out [the Primer Theme documentation](/primer-theme). + +## When to use the `sx` prop + +The `sx` prop provides a lot of power, which means it is an easy tool to abuse. To best make use of it, we recommend following these guidelines: + +* Use the `sx` prop for small stylistic changes to components. For more substantial changes, consider abstracting your style changes into your own wrapper component. +* Use [system props](/system-props) instead of the `sx` prop whenever possible. +* Avoid nesting and pseudo-selectors in `sx` prop values when possible. + +## Basic example + +This example demonstrates applying a bottom border to `Heading`, a component that does not receive `BORDER` system props. The `borderBottomWidth` value comes from `theme.borderWidths` and `borderBottomColor` comes from `theme.colors`. + +```jsx live +Heading + + + Heading with bottom border + +``` + +## Responsive values + +Just like [values passed to system props](https://styled-system.com/responsive-styles), values in the `sx` prop can be provided as arrays to provide responsive styling. + +```jsx live + + Responsive background color + +``` + +## Nesting, pseudo-classes, and pseudo-elements + +The `sx` prop also allows for declaring styles based on media queries, psueudo-classes, and pseudo-elements. This example, though contrived, demonstrates the ability: + +```jsx live + *': { + borderWidth: 1, + borderColor: 'border.gray', + borderStyle: 'solid', + borderBottomWidth: 0, + padding: 2, + ':last-child': { + borderBottomWidth: 1 + }, + ':hover': { + bg: 'gray.1' + } + } +}}> + First + Second + Third + +``` diff --git a/docs/content/primer-theme.md b/docs/content/primer-theme.md index d29173ce227..0a5e58a0a9a 100644 --- a/docs/content/primer-theme.md +++ b/docs/content/primer-theme.md @@ -4,25 +4,23 @@ title: Primer Theme import {theme} from '@primer/components' -Primer Components come with built-in access to our Primer theme. The [theme file](https://github.com/primer/components/blob/master/src/theme.js) contains an object which holds values -for common variables such as color, fonts, box shadows, and more. Our theme file pulls many of its color and typography values from [primer-primitives](https://github.com/primer/primer-primitives). +Primer Components come with built-in access to our Primer theme. The [theme file](https://github.com/primer/components/blob/master/src/theme.js) contains an object which holds values for common variables such as color, fonts, box shadows, and more. Our theme file pulls many of its color and typography values from [primer-primitives](https://github.com/primer/primer-primitives). -Many of our theme keys correspond to system props on our components. For example, if you'd like to set the max width on a `` set the `maxWidth` prop to `medium`: -`` +Many of our theme keys correspond to system props on our components. For example, if you'd like to set the max width on a `` set the `maxWidth` prop to `medium`: `` -In the background, [styled-system](https://github.com/jxnblk/styled-system) does the work of finding the `medium` value from `maxWidth` key in the theme file and applying the corresponding CSS. +In the background, [styled-system](https://github.com/styled-system/styled-system) does the work of finding the `medium` value from `maxWidth` key in the theme file and applying the corresponding CSS. Our full theme can be found [here](https://github.com/primer/components/blob/master/src/theme.js). - ### Custom Theming + Custom theming is an optional way to override the Primer values that control color, spacing, typography, and other aspects of our components. There are two ways to change the theme of Primer components: 1. You can override the entire theme for an entire tree of components using the `` from [styled-components]: - ```jsx + ```javascript import {Block, Button, Text, theme as primer} from '@primer/components' import {ThemeProvider} from 'styled-components' @@ -46,29 +44,29 @@ There are two ways to change the theme of Primer components: ``` **⚠️ Note: [styled-components]'s `` only allows exactly one child.** -2. You can merge the Primer theme with your custom theme using Object.assign: -```jsx -import {ThemeProvider} from `styled-components` -import {theme} from '@primer/components' +2. You can merge the Primer theme with your custom theme using Object.assign: -const customTheme = { ... } + ```javascript + import {ThemeProvider} from `styled-components` + import {theme} from '@primer/components' + const customTheme = { ... } -const App = (props) => { - return ( -
- // matching keys in customTheme will override keys in the Primer theme -
your app here
-
-
- ) -} -``` + const App = (props) => { + return ( +
+ // matching keys in customTheme will override keys in the Primer theme +
your app here
+
+
+ ) + } + ``` 3. You can theme individual components by passing the `theme` prop directly: - ```jsx + ```javascript import {Text} from '@primer/components' const theme = { @@ -84,7 +82,6 @@ const App = (props) => { **☝️ This is an intentionally convoluted example, since you can use `` out of the box.** - Read the [styled-system docs](https://styled-system.com/#theming) for more information on theming in styled-system. [styled-components]: https://styled-components.com/ diff --git a/docs/gatsby-config.js b/docs/gatsby-config.js index 7262fd12997..5354f19e60c 100644 --- a/docs/gatsby-config.js +++ b/docs/gatsby-config.js @@ -18,7 +18,7 @@ module.exports = { options: { alias: { '@primer/components': path.resolve(__dirname, '../src'), - 'styled-components': path.resolve(__dirname, 'node_modules', 'styled-components'), + 'styled-components': path.resolve(__dirname, '..', 'node_modules', 'styled-components'), 'react': path.resolve(__dirname, 'node_modules', 'react'), } } diff --git a/docs/src/@primer/gatsby-theme-doctocat/nav.yml b/docs/src/@primer/gatsby-theme-doctocat/nav.yml index 29e1666c0d2..cd112a97472 100644 --- a/docs/src/@primer/gatsby-theme-doctocat/nav.yml +++ b/docs/src/@primer/gatsby-theme-doctocat/nav.yml @@ -13,6 +13,9 @@ - title: Philosophy url: /philosophy + - title: Overriding Styles + url: /overriding-styles + - title: Components url: / children: diff --git a/index.d.ts b/index.d.ts index 711c04bf6f9..0c21cff4f9b 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,6 +1,7 @@ declare module '@primer/components' { type Omit = Pick> import * as StyledSystem from 'styled-system' + import {SystemStyleObject} from '@styled-system/css' import * as StyledComponents from 'styled-components' import * as History from 'history' @@ -8,6 +9,7 @@ declare module '@primer/components' { as?: React.ReactType className?: string css?: string + sx?: SystemStyleObject title?: string // NOTE(@mxstbr): Necessary workaround to make work to?: History.LocationDescriptor @@ -80,6 +82,7 @@ declare module '@primer/components' { export interface ButtonProps extends BaseProps, CommonProps, + LayoutProps, StyledSystem.FontSizeProps, Omit, 'color'> { variant?: 'small' | 'medium' | 'large' diff --git a/package.json b/package.json index 7f1534aa7a0..c233216e7ab 100644 --- a/package.json +++ b/package.json @@ -36,9 +36,10 @@ "author": "GitHub, Inc.", "license": "MIT", "dependencies": { - "@primer/octicons-react": "^9.2.0", + "@primer/octicons-react": "^9.6.0", "@primer/primitives": "3.0.0", "@reach/dialog": "0.3.0", + "@styled-system/css": "5.1.5", "@styled-system/prop-types": "5.1.2", "@styled-system/props": "5.1.4", "@styled-system/theme-get": "5.1.2", diff --git a/src/Avatar.js b/src/Avatar.js index 83db587e413..44488d78c65 100644 --- a/src/Avatar.js +++ b/src/Avatar.js @@ -1,5 +1,6 @@ -import PropTypes from 'prop-types' import styled from 'styled-components' +import PropTypes from 'prop-types' +import sx from './sx' import {get} from './constants' import {space} from 'styled-system' import systemPropTypes from '@styled-system/prop-types' @@ -22,6 +23,7 @@ const Avatar = styled.img.attrs(props => ({ vertical-align: middle; ${borderRadius}; ${space}; + ${sx}; ` Avatar.defaultProps = { @@ -35,6 +37,7 @@ Avatar.propTypes = { size: PropTypes.number, src: PropTypes.string, ...systemPropTypes.space, + ...sx.propTypes, theme: PropTypes.object } diff --git a/src/AvatarStack.js b/src/AvatarStack.js index 1a91360b2ae..6371a0c3513 100644 --- a/src/AvatarStack.js +++ b/src/AvatarStack.js @@ -1,6 +1,7 @@ import React from 'react' import PropTypes from 'prop-types' import styled, {css} from 'styled-components' +import sx from './sx' import {get, COMMON} from './constants' import theme from './theme' @@ -22,6 +23,7 @@ const AvatarStackWrapper = styled.span` min-width: ${props => (props.count === 1 ? '26px' : props.count === 2 ? '36px' : '46px')}; height: 20px; ${COMMON} + ${sx}; ` const AvatarStackBody = styled.span` @@ -152,6 +154,7 @@ AvatarStack.defaultProps = { AvatarStack.propTypes = { ...COMMON.propTypes, - alignRight: PropTypes.bool + alignRight: PropTypes.bool, + ...sx.propTypes } export default AvatarStack diff --git a/src/BorderBox.js b/src/BorderBox.js index f53ac7ad007..36e46ce54fa 100644 --- a/src/BorderBox.js +++ b/src/BorderBox.js @@ -1,10 +1,14 @@ import styled from 'styled-components' +import sx from './sx' import PropTypes from 'prop-types' import Box from './Box' import theme from './theme' import {BORDER} from './constants' -const BorderBox = styled(Box)(BORDER) +const BorderBox = styled(Box)` + ${BORDER}; + ${sx}; +` BorderBox.defaultProps = { theme, @@ -15,9 +19,10 @@ BorderBox.defaultProps = { } BorderBox.propTypes = { - theme: PropTypes.object, ...Box.propTypes, - ...BORDER.propTypes + ...BORDER.propTypes, + ...sx.propTypes, + theme: PropTypes.object } export default BorderBox diff --git a/src/Box.js b/src/Box.js index 158564c07ff..124a1703dd6 100644 --- a/src/Box.js +++ b/src/Box.js @@ -1,5 +1,6 @@ import styled from 'styled-components' import PropTypes from 'prop-types' +import sx from './sx' import {COMMON, FLEX, LAYOUT} from './constants' import theme from './theme' @@ -7,6 +8,7 @@ const Box = styled.div` ${COMMON} ${FLEX} ${LAYOUT} + ${sx}; ` Box.defaultProps = {theme} @@ -15,6 +17,7 @@ Box.propTypes = { ...COMMON.propTypes, ...FLEX.propTypes, ...LAYOUT.propTypes, + ...sx.propTypes, theme: PropTypes.object } diff --git a/src/BranchName.js b/src/BranchName.js index 3041fb8e756..3c7b342de40 100644 --- a/src/BranchName.js +++ b/src/BranchName.js @@ -1,5 +1,6 @@ import PropTypes from 'prop-types' import styled from 'styled-components' +import sx from './sx' import theme from './theme' import {COMMON, get} from './constants' @@ -12,6 +13,7 @@ const BranchName = styled.a` background-color: #eaf5ff; border-radius: 3px; ${COMMON}; + ${sx}; ` BranchName.defaultProps = { @@ -21,6 +23,7 @@ BranchName.defaultProps = { BranchName.propTypes = { href: PropTypes.string, ...COMMON.propTypes, + ...sx.propTypes, theme: PropTypes.object } diff --git a/src/Breadcrumbs.js b/src/Breadcrumbs.js index ab316bedacc..8c6d0263d32 100644 --- a/src/Breadcrumbs.js +++ b/src/Breadcrumbs.js @@ -2,6 +2,7 @@ import React from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import styled from 'styled-components' +import sx from './sx' import {COMMON, FLEX, get} from './constants' import theme from './theme' import Box from './Box' @@ -46,6 +47,7 @@ const Breadcrumb = styled(BreadcrumbBase)` justify-content: space-between; ${COMMON}; ${FLEX}; + ${sx}; ` Breadcrumb.Item = styled.a.attrs(props => ({ @@ -65,6 +67,7 @@ Breadcrumb.Item = styled.a.attrs(props => ({ pointer-events: none; } ${COMMON} + ${sx}; ` Breadcrumb.defaultProps = { @@ -72,18 +75,24 @@ Breadcrumb.defaultProps = { } Breadcrumb.propTypes = { - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } +Breadcrumb.displayName = 'Breadcrumb' + Breadcrumb.Item.defaultProps = { theme } Breadcrumb.Item.propTypes = { - as: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), + as: PropTypes.oneOfType([PropTypes.string, PropTypes.elementType]), href: PropTypes.string, selected: PropTypes.bool, + ...sx.propTypes, ...COMMON.propTypes } +Breadcrumb.Item.displayName = 'Breadcrumb.Item' + export default Breadcrumb diff --git a/src/Button.js b/src/Button.js index 36c30aa44c3..93dd2420b73 100644 --- a/src/Button.js +++ b/src/Button.js @@ -1,7 +1,6 @@ -import PropTypes from 'prop-types' import styled from 'styled-components' -import systemPropTypes from '@styled-system/prop-types' -import {COMMON, get} from './constants' +import sx from './sx' +import {get} from './constants' import theme from './theme' import ButtonBase from './ButtonBase' @@ -34,6 +33,8 @@ const Button = styled(ButtonBase)` background-color: ${get('buttons.default.bg.disabled')}; border-color: ${get('buttons.default.border.disabled')}; } + + ${sx}; ` Button.defaultProps = { @@ -41,9 +42,8 @@ Button.defaultProps = { } Button.propTypes = { - theme: PropTypes.object, - ...COMMON.propTypes, - ...systemPropTypes.layout + ...ButtonBase.propTypes, + ...sx.propTypes } export default Button diff --git a/src/ButtonBase.js b/src/ButtonBase.js index 3b90de1863e..980d7658e97 100644 --- a/src/ButtonBase.js +++ b/src/ButtonBase.js @@ -1,9 +1,9 @@ import PropTypes from 'prop-types' import styled from 'styled-components' -import {COMMON} from './constants' +import {COMMON, LAYOUT} from './constants' import theme from './theme' import buttonBaseStyles from './ButtonStyles' -import {compose, variant, layout, fontSize} from 'styled-system' +import {compose, variant, fontSize} from 'styled-system' import systemPropTypes from '@styled-system/prop-types' const variants = variant({ @@ -27,7 +27,7 @@ const ButtonBase = styled.button.attrs(({disabled, onClick}) => ({ }))` ${buttonBaseStyles} ${variants} - ${compose(fontSize, COMMON, layout)} + ${compose(fontSize, COMMON, LAYOUT)} ` ButtonBase.defaultProps = { @@ -36,7 +36,7 @@ ButtonBase.defaultProps = { } ButtonBase.propTypes = { - as: PropTypes.oneOfType([PropTypes.oneOf(['button', 'a', 'summary', 'input']), PropTypes.func]), + as: PropTypes.oneOfType([PropTypes.oneOf(['button', 'a', 'summary', 'input']), PropTypes.elementType]), children: PropTypes.node, disabled: PropTypes.bool, fontSize: systemPropTypes.typography.fontSize, @@ -44,7 +44,7 @@ ButtonBase.propTypes = { theme: PropTypes.object, variant: PropTypes.oneOf(['small', 'medium', 'large']), ...COMMON.propTypes, - ...systemPropTypes.layout + ...LAYOUT.propTypes } export default ButtonBase diff --git a/src/ButtonDanger.js b/src/ButtonDanger.js index b8f74bb58ce..fdb72968ccb 100644 --- a/src/ButtonDanger.js +++ b/src/ButtonDanger.js @@ -1,6 +1,8 @@ import styled from 'styled-components' import ButtonBase from './ButtonBase' import {get} from './constants' +import theme from './theme' +import sx from './sx' const ButtonDanger = styled(ButtonBase)` color: ${get('buttons.danger.color.default')}; @@ -32,6 +34,17 @@ const ButtonDanger = styled(ButtonBase)` background-color: ${get('buttons.danger.bg.disabled')}; border: 1px solid ${get('buttons.danger.border.default')}; } + + ${sx}; ` +ButtonDanger.defaultProps = { + theme +} + +ButtonDanger.propTypes = { + ...ButtonBase.propTypes, + ...sx.propTypes +} + export default ButtonDanger diff --git a/src/ButtonGroup.js b/src/ButtonGroup.js index 1ac188c8f32..6cb77d99512 100644 --- a/src/ButtonGroup.js +++ b/src/ButtonGroup.js @@ -1,6 +1,8 @@ import styled from 'styled-components' import {get} from './constants' import Box from './Box' +import theme from './theme' +import sx from './sx' const ButtonGroup = styled(Box)` vertical-align: middle; @@ -41,12 +43,18 @@ const ButtonGroup = styled(Box)` z-index: 1; } } + + ${sx}; ` + ButtonGroup.defaultProps = { - display: 'inline-block' + display: 'inline-block', + theme } + ButtonGroup.propTypes = { - ...Box.propTypes + ...Box.propTypes, + ...sx.propTypes } export default ButtonGroup diff --git a/src/ButtonOutline.js b/src/ButtonOutline.js index abc6b9a812d..526bdb01ec6 100644 --- a/src/ButtonOutline.js +++ b/src/ButtonOutline.js @@ -1,6 +1,8 @@ import styled from 'styled-components' import ButtonBase from './ButtonBase' import {get} from './constants' +import theme from './theme' +import sx from './sx' const ButtonOutline = styled(ButtonBase)` color: ${get('buttons.outline.color.default')}; @@ -32,6 +34,17 @@ const ButtonOutline = styled(ButtonBase)` border-color: ${get('buttons.outline.border.default')}; background-color: ${get('buttons.outline.bg.disabled')}; } + + ${sx}; ` +ButtonOutline.defaultProps = { + theme +} + +ButtonOutline.propTypes = { + ...ButtonBase.propTypes, + ...sx.propTypes +} + export default ButtonOutline diff --git a/src/ButtonPrimary.js b/src/ButtonPrimary.js index 02388e237fe..ab27444b7d7 100644 --- a/src/ButtonPrimary.js +++ b/src/ButtonPrimary.js @@ -1,6 +1,8 @@ import styled from 'styled-components' import ButtonBase from './ButtonBase' import {get} from './constants' +import theme from './theme' +import sx from './sx' const ButtonPrimary = styled(ButtonBase)` color: ${get('buttons.primary.color.default')}; @@ -30,6 +32,17 @@ const ButtonPrimary = styled(ButtonBase)` background-color: ${get('buttons.primary.bg.disabled')}; border-color: ${get('buttons.primary.border.disabled')}; } + + ${sx}; ` +ButtonPrimary.defaultProps = { + theme +} + +ButtonPrimary.propTypes = { + ...ButtonBase.propTypes, + ...sx.propTypes +} + export default ButtonPrimary diff --git a/src/ButtonTableList.js b/src/ButtonTableList.js index 9a767522875..4bdbdc2bf85 100644 --- a/src/ButtonTableList.js +++ b/src/ButtonTableList.js @@ -1,6 +1,8 @@ import styled from 'styled-components' +import PropTypes from 'prop-types' import {COMMON, LAYOUT, TYPOGRAPHY, get} from './constants' import theme from './theme' +import sx from './sx' const ButtonTableList = styled.summary` display: inline-block; @@ -40,10 +42,19 @@ const ButtonTableList = styled.summary` ${COMMON} ${TYPOGRAPHY} ${LAYOUT} + ${sx}; ` ButtonTableList.defaultProps = { theme } +ButtonTableList.propTypes = { + theme: PropTypes.object, + ...sx.propTypes, + ...COMMON.propTypes, + ...TYPOGRAPHY.propTypes, + ...LAYOUT.propTypes +} + export default ButtonTableList diff --git a/src/CircleBadge.js b/src/CircleBadge.js index 7529eebf7e8..731df05129a 100644 --- a/src/CircleBadge.js +++ b/src/CircleBadge.js @@ -4,6 +4,7 @@ import Octicon from '@primer/octicons-react' import {COMMON, get} from './constants' import isNumeric from './utils/isNumeric' import theme from './theme' +import sx from './sx' const variantSizes = { small: 56, @@ -27,15 +28,16 @@ const CircleBadge = styled.div` border-radius: 50%; box-shadow: ${get('shadows.medium')}; ${COMMON} ${sizeStyles}; + ${sx}; ` -const Icon = styled(Octicon)` +CircleBadge.Icon = styled(Octicon)` max-width: 60% !important; height: auto !important; max-height: 55% !important; ${COMMON}; + ${sx}; ` -CircleBadge.Icon = Icon CircleBadge.defaultProps = { inline: false, @@ -48,16 +50,20 @@ CircleBadge.propTypes = { size: PropTypes.number, theme: PropTypes.object, variant: PropTypes.oneOf(['small', 'medium', 'large']), - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } CircleBadge.Icon.defaultProps = { theme } -CircleBadge.Icon.propsTypes = { +CircleBadge.Icon.propTypes = { theme: PropTypes.object, - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } +CircleBadge.Icon.displayName = 'CircleBadge.Icon' + export default CircleBadge diff --git a/src/CounterLabel.js b/src/CounterLabel.js index a0c7ae26f98..00164a80ae5 100644 --- a/src/CounterLabel.js +++ b/src/CounterLabel.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types' import styled from 'styled-components' import {COMMON, get} from './constants' import theme from './theme' +import sx from './sx' const colorStyles = ({scheme, ...props}) => { return { @@ -39,6 +40,8 @@ const CounterLabel = styled.span` &:empty { visibility: hidden; } + + ${sx}; ` CounterLabel.defaultProps = { @@ -49,7 +52,8 @@ CounterLabel.propTypes = { children: PropTypes.node, scheme: PropTypes.oneOf(['gray', 'gray-light']), theme: PropTypes.object, - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } export default CounterLabel diff --git a/src/Details.js b/src/Details.js index 0c097a48dbe..f7c43d2f21a 100644 --- a/src/Details.js +++ b/src/Details.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types' import styled from 'styled-components' import {COMMON} from './constants' import theme from './theme' +import sx from './sx' // The
element is not yet supported in Edge so we have to use a polyfill. // We have to check if window is defined before importing the polyfill @@ -21,6 +22,7 @@ const StyledDetails = styled('details')` } ${COMMON} + ${sx}; ` function getRenderer(children) { return typeof children === 'function' ? children : () => children @@ -90,7 +92,8 @@ Details.propTypes = { overlay: PropTypes.bool, render: PropTypes.func, theme: PropTypes.object, - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } export default Details diff --git a/src/Dialog.js b/src/Dialog.js index b00d4c46ad1..5f02271305d 100644 --- a/src/Dialog.js +++ b/src/Dialog.js @@ -3,12 +3,11 @@ import {Dialog as ReachDialog} from '@reach/dialog' import raw from 'raw.macro' import styled, {createGlobalStyle} from 'styled-components' import PropTypes from 'prop-types' -import {space, color} from 'styled-system' -import systemPropTypes from '@styled-system/prop-types' import {X} from '@primer/octicons-react' import StyledOcticon from './StyledOcticon' -import {LAYOUT} from './constants' +import {COMMON, LAYOUT} from './constants' import theme from './theme' +import sx from './sx' import Text from './Text' import Flex from './Flex' @@ -36,8 +35,8 @@ export const StyledDialog = styled(ReachDialog)` } ${LAYOUT} - ${space} - ${color} + ${COMMON} + ${sx}; ` const UnstyledButton = styled(Flex).attrs({ @@ -59,6 +58,8 @@ const DialogHeaderBase = styled(Flex)` @media screen and (max-width: 750px) { border-radius: 0px; } + + ${sx}; ` function DialogHeader({theme, children, ...rest}) { @@ -77,7 +78,7 @@ function DialogHeader({theme, children, ...rest}) { ) } -const Dialog = ({children, ...props}) => { +function Dialog({children, ...props}) { return ( <> @@ -94,12 +95,12 @@ const Dialog = ({children, ...props}) => { Dialog.defaultProps = {theme} Dialog.propTypes = { + ...COMMON.propTypes, ...LAYOUT.propTypes, - ...systemPropTypes.space, - ...systemPropTypes.color, children: PropTypes.node.isRequired, isOpen: PropTypes.bool.isRequired, onDismiss: PropTypes.func.isRequired, + ...sx.propTypes, theme: PropTypes.object } @@ -112,5 +113,7 @@ DialogHeader.propTypes = { ...Flex.propTypes } +DialogHeader.displayName = 'Dialog.Header' + Dialog.Header = DialogHeader export default Dialog diff --git a/src/Dropdown.js b/src/Dropdown.js index a2f34b60e27..d2e539dec87 100644 --- a/src/Dropdown.js +++ b/src/Dropdown.js @@ -6,6 +6,7 @@ import Details from './Details' import {COMMON, get} from './constants' import getDirectionStyles from './DropdownStyles' import theme from './theme' +import sx from './sx' const StyledDetails = styled(Details)` position: relative; @@ -39,7 +40,8 @@ Dropdown.Caret = styled.div` height: 0; vertical-align: middle; width: 0; - ${COMMON} + ${COMMON}; + ${sx}; ` Dropdown.Menu = styled.ul` @@ -85,6 +87,7 @@ Dropdown.Menu = styled.ul` } ${props => (props.direction ? getDirectionStyles(props.theme, props.direction) : '')}; ${COMMON}; + ${sx}; ` Dropdown.Item = styled.li` @@ -120,31 +123,42 @@ Dropdown.Item = styled.li` outline: none; } ${COMMON}; + ${sx}; ` Dropdown.Menu.propTypes = { direction: PropTypes.oneOf(['ne', 'e', 'se', 's', 'sw', 'w']), - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } Dropdown.Menu.defaultProps = { direction: 'sw', theme } +Dropdown.Menu.displayName = 'Dropdown.Menu' Dropdown.Item.defaultProps = {theme} Dropdown.Item.propTypes = { - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } +Dropdown.Item.displayName = 'Dropdown.Item' -Dropdown.Button.defaultProps = {theme} +Dropdown.Button.defaultProps = {theme, ...Button.defaultProps} +Dropdown.Button.propTypes = { + ...Button.propTypes +} +Dropdown.Button.displayName = 'Dropdown.Button' Dropdown.Caret.defaultProps = {theme} Dropdown.Caret.propTypes = { - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } +Dropdown.Caret.displayName = 'Dropdown.Caret' -Dropdown.defaultProps = {theme} +Dropdown.defaultProps = {theme, ...Details.defaultProps} Dropdown.propTypes = { ...Details.propTypes, ...COMMON.propTypes diff --git a/src/FilterList.js b/src/FilterList.js index 14ac59a555c..96a07dfc8ff 100644 --- a/src/FilterList.js +++ b/src/FilterList.js @@ -4,6 +4,7 @@ import PropTypes from 'prop-types' import styled from 'styled-components' import {COMMON, get} from './constants' import theme from './theme' +import sx from './sx' function ItemBase({children, count, theme, ...rest}) { return ( @@ -44,7 +45,8 @@ const Item = styled(ItemBase)` float: right; font-weight: ${get('fontWeights.bold')}; } - ${COMMON}: ; + ${COMMON}; + ${sx}; ` const FilterListBase = ({children, theme, ...rest}) => { @@ -58,6 +60,7 @@ const FilterListBase = ({children, theme, ...rest}) => { const FilterList = styled(FilterListBase)` list-style-type: none; ${COMMON}; + ${sx}; ` FilterList.defaultProps = { @@ -69,7 +72,8 @@ FilterList.defaultProps = { FilterList.propTypes = { children: PropTypes.node, small: PropTypes.bool, - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } FilterList.Item = Item @@ -79,13 +83,16 @@ FilterList.Item.defaultProps = { } FilterList.Item.propTypes = { - as: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), + as: PropTypes.oneOfType([PropTypes.string, PropTypes.elementType]), children: PropTypes.node, className: PropTypes.string, count: PropTypes.string, selected: PropTypes.bool, theme: PropTypes.object, - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } +FilterList.Item.displayName = 'FilterList.Item' + export default FilterList diff --git a/src/Flash.js b/src/Flash.js index 2aace8f776c..a65d0058e4c 100644 --- a/src/Flash.js +++ b/src/Flash.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types' import styled from 'styled-components' import {COMMON, get} from './constants' import theme from './theme' +import sx from './sx' const schemeMap = { green: {color: 'colors.green.8', bg: 'colors.green.1'}, @@ -25,6 +26,7 @@ const Flash = styled.div` margin-bottom: 0; } ${COMMON}; + ${sx}; ` Flash.defaultProps = { @@ -37,7 +39,8 @@ Flash.propTypes = { full: PropTypes.bool, scheme: PropTypes.oneOf(Object.keys(schemeMap)), theme: PropTypes.object, - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } export default Flash diff --git a/src/Heading.js b/src/Heading.js index aaf63fa0856..c8df9d34f70 100644 --- a/src/Heading.js +++ b/src/Heading.js @@ -1,4 +1,5 @@ import styled from 'styled-components' +import sx from './sx' import PropTypes from 'prop-types' import {TYPOGRAPHY, COMMON, get} from './constants' import theme from './theme' @@ -8,6 +9,7 @@ const Heading = styled.h2` font-size: ${get('fontSizes.5')}; margin: 0; ${TYPOGRAPHY} ${COMMON}; + ${sx}; ` Heading.defaultProps = { @@ -15,8 +17,9 @@ Heading.defaultProps = { } Heading.propTypes = { - theme: PropTypes.object, ...COMMON.propTypes, + ...sx.propTypes, + theme: PropTypes.object, ...TYPOGRAPHY.propTypes } diff --git a/src/Label.js b/src/Label.js index ce3668c29b6..abbf600d1b9 100644 --- a/src/Label.js +++ b/src/Label.js @@ -3,6 +3,7 @@ import styled, {css} from 'styled-components' import {variant, borderColor} from 'styled-system' import theme from './theme' import {COMMON, get} from './constants' +import sx from './sx' const outlineStyles = css` margin-top: -1px; // offsets the 1px border @@ -52,6 +53,7 @@ const Label = styled('span')` ${sizeVariant} ${COMMON} ${props => (props.dropshadow ? 'box-shadow: inset 0 -1px 0 rgba(27, 31, 35, 0.12)' : '')}; ${props => (props.outline ? outlineStyles : '')}; // must be last to override other values + ${sx}; ` Label.defaultProps = { @@ -65,7 +67,8 @@ Label.propTypes = { outline: PropTypes.bool, theme: PropTypes.object, variant: PropTypes.oneOf(['small', 'medium', 'large', 'xl']), - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } export default Label diff --git a/src/LabelGroup.js b/src/LabelGroup.js index f14117d0159..d443ba7b10b 100644 --- a/src/LabelGroup.js +++ b/src/LabelGroup.js @@ -2,6 +2,7 @@ import React from 'react' import styled from 'styled-components' import theme from './theme' import {COMMON, get} from './constants' +import sx from './sx' const transformChildren = children => { return React.Children.map(children, child => { @@ -17,6 +18,7 @@ const StyledLabelGroup = styled.span` & .LabelItem:last-child { margin-right: 0; } + ${sx}; ` const LabelGroup = ({children, ...rest}) => {transformChildren(children)} @@ -26,7 +28,8 @@ LabelGroup.defaultProps = { } LabelGroup.propTypes = { - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } export default LabelGroup diff --git a/src/Link.js b/src/Link.js index e0915715f73..0466251a5ea 100644 --- a/src/Link.js +++ b/src/Link.js @@ -4,6 +4,7 @@ import {system} from 'styled-system' import {COMMON, TYPOGRAPHY, get} from './constants' import theme from './theme' import elementType from './utils/elementType' +import sx from './sx' const buttonStyles = { display: 'inline-block', @@ -34,6 +35,7 @@ const Link = styled.a.attrs(props => ({ } ${props => (props.as === 'button' ? buttonStyles : '')}; ${TYPOGRAPHY} ${COMMON}; + ${sx}; ` Link.defaultProps = { @@ -47,7 +49,8 @@ Link.propTypes = { theme: PropTypes.object, underline: PropTypes.bool, ...TYPOGRAPHY.propTypes, - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } export default Link diff --git a/src/Pagination/Pagination.js b/src/Pagination/Pagination.js index cc7b19da108..1f943796474 100644 --- a/src/Pagination/Pagination.js +++ b/src/Pagination/Pagination.js @@ -1,6 +1,7 @@ import React from 'react' import PropTypes from 'prop-types' import styled, {css} from 'styled-components' +import sx from '../sx' import {get, COMMON} from '../constants' import theme from '../theme' import Box from '../Box' @@ -102,6 +103,7 @@ const PaginationContainer = styled.nav` margin-top: 20px; margin-bottom: 15px; text-align: center; + ${sx}; ` function Pagination({ @@ -148,7 +150,8 @@ Pagination.propTypes = { pageCount: PropTypes.number.isRequired, showPages: PropTypes.bool, surroundingPageCount: PropTypes.number, - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } Pagination.defaultProps = { diff --git a/src/Popover.js b/src/Popover.js index 60baef64dd2..2fb7e6d741c 100644 --- a/src/Popover.js +++ b/src/Popover.js @@ -5,6 +5,7 @@ import {COMMON, LAYOUT, POSITION, get} from './constants' import theme from './theme' import elementType from './utils/elementType' import BorderBox from './BorderBox' +import sx from './sx' const Popover = styled.div.attrs(({className, caret}) => { return { @@ -18,6 +19,7 @@ const Popover = styled.div.attrs(({className, caret}) => { ${COMMON}; ${LAYOUT}; ${POSITION}; + ${sx}; ` Popover.Content = styled(BorderBox)` @@ -196,6 +198,8 @@ Popover.Content = styled(BorderBox)` bottom: calc(${get('space.3')} + 1px); } } + + ${sx}; ` export const CARET_POSITIONS = [ @@ -226,7 +230,8 @@ Popover.propTypes = { theme: PropTypes.object, ...COMMON.propTypes, ...LAYOUT.propTypes, - ...POSITION.propTypes + ...POSITION.propTypes, + ...sx.propTypes } Popover.Content.defaultProps = { @@ -236,7 +241,10 @@ Popover.Content.defaultProps = { Popover.Content.propTypes = { as: elementType, theme: PropTypes.object, - ...BorderBox.propTypes + ...BorderBox.propTypes, + ...sx.propTypes } +Popover.Content.displayName = 'Popover.Content' + export default Popover diff --git a/src/Position.js b/src/Position.js index 7577be7616d..2a26c5d1714 100644 --- a/src/Position.js +++ b/src/Position.js @@ -3,11 +3,13 @@ import PropTypes from 'prop-types' import styled from 'styled-components' import {COMMON, LAYOUT, POSITION} from './constants' import theme from './theme' +import sx from './sx' export const Position = styled.div` ${LAYOUT} ${COMMON} ${POSITION} + ${sx}; ` Position.defaultProps = { @@ -18,21 +20,22 @@ Position.propTypes = { ...COMMON.propTypes, ...LAYOUT.propTypes, ...POSITION.propTypes, + ...sx.propTypes, theme: PropTypes.object } function withPosition(position) { - const WithPosition = props => + const WithPosition = props => WithPosition.propTypes = Position.propTypes WithPosition.defaultProps = Position.defaultProps WithPosition.displayName = `Position.${position}` return WithPosition } -export const Absolute = withPosition('absolute') -export const Fixed = withPosition('fixed') -export const Relative = withPosition('relative') -export const Sticky = withPosition('sticky') +export const Absolute = withPosition('Absolute') +export const Fixed = withPosition('Fixed') +export const Relative = withPosition('Relative') +export const Sticky = withPosition('Sticky') Sticky.defaultProps = { theme, top: 0, diff --git a/src/ProgressBar.js b/src/ProgressBar.js index ab8e48de405..739659f4373 100644 --- a/src/ProgressBar.js +++ b/src/ProgressBar.js @@ -5,6 +5,7 @@ import {layout} from 'styled-system' import systemPropTypes from '@styled-system/prop-types' import theme from './theme' import {COMMON, get} from './constants' +import sx from './sx' const Bar = styled.span` width: ${props => (props.progress ? `${props.progress}%` : 0)}; @@ -25,6 +26,7 @@ const ProgressContainer = styled.span` height: ${props => sizeMap[props.barSize]}; ${COMMON} ${layout.width} + ${sx}; ` const ProgressBar = ({progress, bg, theme, ...rest}) => { @@ -46,6 +48,7 @@ ProgressBar.propTypes = { barSize: PropTypes.oneOf(['small', 'default', 'large']), inline: PropTypes.bool, progress: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + ...sx.propTypes, theme: PropTypes.object, width: systemPropTypes.layout.width } diff --git a/src/SelectMenu/SelectMenu.js b/src/SelectMenu/SelectMenu.js index e6969f11570..102f15bcd29 100644 --- a/src/SelectMenu/SelectMenu.js +++ b/src/SelectMenu/SelectMenu.js @@ -1,6 +1,7 @@ import React, {useRef, useState} from 'react' import styled from 'styled-components' import PropTypes from 'prop-types' +import sx from '../sx' import {COMMON} from '../constants' import theme from '../theme' import {MenuContext} from './SelectMenuContext' @@ -46,6 +47,7 @@ const wrapperStyles = ` const StyledSelectMenu = styled.details` ${wrapperStyles} ${COMMON} + ${sx}; ` // 'as' is spread out because we don't want users to be able to change the tag. @@ -95,7 +97,8 @@ SelectMenu.defaultProps = { SelectMenu.propTypes = { initialTab: PropTypes.string, - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } export default SelectMenu diff --git a/src/SelectMenu/SelectMenuDivider.js b/src/SelectMenu/SelectMenuDivider.js index 4b45477efa5..89826ddfca8 100644 --- a/src/SelectMenu/SelectMenuDivider.js +++ b/src/SelectMenu/SelectMenuDivider.js @@ -1,6 +1,7 @@ import styled, {css} from 'styled-components' import theme from '../theme' import {COMMON, get} from '../constants' +import sx from '../sx' const dividerStyles = css` padding: ${get('space.1')} ${get('space.3')}; @@ -15,6 +16,7 @@ const dividerStyles = css` const SelectMenuDivider = styled.div` ${dividerStyles} ${COMMON} + ${sx}; ` SelectMenuDivider.defaultProps = { @@ -22,7 +24,10 @@ SelectMenuDivider.defaultProps = { } SelectMenuDivider.propTypes = { - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } +SelectMenuDivider.displayName = 'SelectMenu.Divider' + export default SelectMenuDivider diff --git a/src/SelectMenu/SelectMenuFilter.js b/src/SelectMenu/SelectMenuFilter.js index 6f2add13320..1066e925e37 100644 --- a/src/SelectMenu/SelectMenuFilter.js +++ b/src/SelectMenu/SelectMenuFilter.js @@ -5,6 +5,7 @@ import {COMMON, get} from '../constants' import theme from '../theme' import TextInput from '../TextInput' import {MenuContext} from './SelectMenuContext' +import sx from '../sx' const StyledForm = styled.form` padding: ${get('space.3')}; @@ -16,9 +17,11 @@ const StyledForm = styled.form` @media (min-width: ${get('breakpoints.0')}) { padding: ${get('space.2')}; } + + ${sx}; ` -function SelectMenuFilter({theme, value, ...rest}) { +function SelectMenuFilter({theme, value, sx, ...rest}) { const inputRef = useRef(null) const {open} = useContext(MenuContext) @@ -28,8 +31,9 @@ function SelectMenuFilter({theme, value, ...rest}) { inputRef.current.focus() } }, [open]) + return ( - + ) @@ -41,7 +45,10 @@ SelectMenuFilter.defaultProps = { SelectMenuFilter.propTypes = { ...COMMON.propTypes, + ...sx.propTypes, value: PropTypes.string } +SelectMenuFilter.displayName = 'SelectMenu.Filter' + export default SelectMenuFilter diff --git a/src/SelectMenu/SelectMenuFooter.js b/src/SelectMenu/SelectMenuFooter.js index a6d70ea15e5..a3313ebce2b 100644 --- a/src/SelectMenu/SelectMenuFooter.js +++ b/src/SelectMenu/SelectMenuFooter.js @@ -1,6 +1,7 @@ import styled, {css} from 'styled-components' import {COMMON, get} from '../constants' import theme from '../theme' +import sx from '../sx' const footerStyles = css` margin-top: -1px; @@ -18,6 +19,7 @@ const footerStyles = css` const SelectMenuFooter = styled.footer` ${footerStyles} ${COMMON} + ${sx}; ` SelectMenuFooter.defaultProps = { @@ -25,7 +27,10 @@ SelectMenuFooter.defaultProps = { } SelectMenuFooter.propTypes = { - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } +SelectMenuFooter.displayName = 'SelectMenu.Footer' + export default SelectMenuFooter diff --git a/src/SelectMenu/SelectMenuHeader.js b/src/SelectMenu/SelectMenuHeader.js index 5d8d3db98b8..b05b521641d 100644 --- a/src/SelectMenu/SelectMenuHeader.js +++ b/src/SelectMenu/SelectMenuHeader.js @@ -1,7 +1,9 @@ import React from 'react' import styled from 'styled-components' +import PropTypes from 'prop-types' import {get, COMMON, TYPOGRAPHY} from '../constants' import theme from '../theme' +import sx from '../sx' // SelectMenu.Header is intentionally not exported, it's an internal component used in // SelectMenu.Modal @@ -29,6 +31,8 @@ const StyledHeader = styled.header` padding-top: ${get('space.2')}; padding-bottom: ${get('space.2')}; } + + ${sx}; ` const SelectMenuHeader = ({children, theme, ...rest}) => { return ( @@ -42,4 +46,13 @@ SelectMenuHeader.defaultProps = { theme } +SelectMenuHeader.propTypes = { + theme: PropTypes.object, + ...COMMON.propTypes, + ...TYPOGRAPHY.propTypes, + ...sx.propTypes +} + +SelectMenuHeader.displayName = 'SelectMenu.Header' + export default SelectMenuHeader diff --git a/src/SelectMenu/SelectMenuItem.js b/src/SelectMenu/SelectMenuItem.js index 2314cfee23a..bc5214f37be 100644 --- a/src/SelectMenu/SelectMenuItem.js +++ b/src/SelectMenu/SelectMenuItem.js @@ -6,6 +6,7 @@ import {MenuContext} from './SelectMenuContext' import {COMMON, get} from '../constants' import StyledOcticon from '../StyledOcticon' import theme from '../theme' +import sx from '../sx' export const listItemStyles = css` display: flex; @@ -93,6 +94,7 @@ const StyledItem = styled.a.attrs(() => ({ }))` ${listItemStyles} ${COMMON} + ${sx}; ` // 'as' is spread out because we don't want users to be able to change the tag. using something @@ -124,7 +126,10 @@ SelectMenuItem.defaultProps = { SelectMenuItem.propTypes = { selected: PropTypes.bool, - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } +SelectMenuItem.displayName = 'SelectMenu.Item' + export default SelectMenuItem diff --git a/src/SelectMenu/SelectMenuList.js b/src/SelectMenu/SelectMenuList.js index b93dbb114d1..b16afdab4ff 100644 --- a/src/SelectMenu/SelectMenuList.js +++ b/src/SelectMenu/SelectMenuList.js @@ -1,6 +1,7 @@ import styled, {css} from 'styled-components' import theme from '../theme' import {COMMON, get} from '../constants' +import sx from '../sx' const listStyles = css` position: relative; @@ -32,13 +33,17 @@ const listStyles = css` const SelectMenuList = styled.div` ${listStyles} ${COMMON} + ${sx}; ` SelectMenuList.defaultProps = { theme } SelectMenuList.propTypes = { - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } +SelectMenuList.displayName = 'SelectMenu.List' + export default SelectMenuList diff --git a/src/SelectMenu/SelectMenuModal.js b/src/SelectMenu/SelectMenuModal.js index ec5b2c5ed56..fa8f937d47c 100644 --- a/src/SelectMenu/SelectMenuModal.js +++ b/src/SelectMenu/SelectMenuModal.js @@ -2,6 +2,7 @@ import React from 'react' import styled, {keyframes, css} from 'styled-components' import {COMMON, get} from '../constants' import theme from '../theme' +import sx from '../sx' const animateModal = keyframes` 0% { @@ -82,6 +83,7 @@ const Modal = styled.div` const ModalWrapper = styled.div` ${modalWrapperStyles} ${COMMON} + ${sx}; ` const SelectMenuModal = ({children, theme, ...rest}) => { @@ -97,7 +99,10 @@ SelectMenuModal.defaultProps = { } SelectMenuModal.propTypes = { - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } +SelectMenuModal.displayName = 'SelectMenu.Modal' + export default SelectMenuModal diff --git a/src/SelectMenu/SelectMenuTab.js b/src/SelectMenu/SelectMenuTab.js index 51c6ede459a..5e668c0a71a 100644 --- a/src/SelectMenu/SelectMenuTab.js +++ b/src/SelectMenu/SelectMenuTab.js @@ -5,6 +5,7 @@ import styled, {css} from 'styled-components' import {MenuContext} from './SelectMenuContext' import {get, COMMON} from '../constants' import theme from '../theme' +import sx from '../sx' const tabStyles = css` flex: 1; @@ -47,6 +48,7 @@ const tabStyles = css` const StyledTab = styled.button` ${tabStyles} ${COMMON} + ${sx}; ` const SelectMenuTab = ({tabName, index, className, onClick, ...rest}) => { @@ -89,7 +91,10 @@ SelectMenuTab.propTypes = { index: PropTypes.number, onClick: PropTypes.func, tabName: PropTypes.string, - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } +SelectMenuTab.displayName = 'SelectMenu.Tab' + export default SelectMenuTab diff --git a/src/SelectMenu/SelectMenuTabPanel.js b/src/SelectMenu/SelectMenuTabPanel.js index 79bc7c3e403..0eddb9d3cb2 100644 --- a/src/SelectMenu/SelectMenuTabPanel.js +++ b/src/SelectMenu/SelectMenuTabPanel.js @@ -5,6 +5,7 @@ import {MenuContext} from './SelectMenuContext' import SelectMenuList from './SelectMenuList' import theme from '../theme' import {COMMON, get} from '../constants' +import sx from '../sx' const TabPanelBase = ({tabName, className, children, ...rest}) => { const menuContext = useContext(MenuContext) @@ -18,6 +19,7 @@ const TabPanelBase = ({tabName, className, children, ...rest}) => { const TabPanel = styled(TabPanelBase)` border-top: ${get('borderWidths.1')} solid ${get('colors.border.gray')}; ${COMMON} + ${sx}; ` TabPanel.defaultProps = { @@ -26,7 +28,10 @@ TabPanel.defaultProps = { TabPanel.propTypes = { tabName: PropTypes.string, - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } +TabPanel.displayName = 'SelectMenu.TabPanel' + export default TabPanel diff --git a/src/SelectMenu/SelectMenuTabs.js b/src/SelectMenu/SelectMenuTabs.js index 7e665a2c049..c29af373eb4 100644 --- a/src/SelectMenu/SelectMenuTabs.js +++ b/src/SelectMenu/SelectMenuTabs.js @@ -2,6 +2,7 @@ import React from 'react' import styled, {css} from 'styled-components' import {COMMON, get} from '../constants' import theme from '../theme' +import sx from '../sx' const tabWrapperStyles = css` display: flex; @@ -33,6 +34,7 @@ const Tabs = ({children, ...rest}) => { const SelectMenuTabs = styled(Tabs)` ${tabWrapperStyles} ${COMMON} + ${sx}; ` SelectMenuTabs.defaultProps = { @@ -40,7 +42,10 @@ SelectMenuTabs.defaultProps = { } SelectMenuTabs.propTypes = { - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } +SelectMenuTabs.displayName = 'SelectMenu.Tabs' + export default SelectMenuTabs diff --git a/src/SideNav.js b/src/SideNav.js index e09ef66fb7d..2715e9ca537 100644 --- a/src/SideNav.js +++ b/src/SideNav.js @@ -7,6 +7,7 @@ import theme from './theme' import elementType from './utils/elementType' import Link from './Link' import BorderBox from './BorderBox' +import sx from './sx' function SideNavBase({variant, className, bordered, children, ...props}) { const variantClassName = variant === 'lightweight' ? 'lightweight' : 'normal' @@ -38,6 +39,7 @@ const SideNav = styled(SideNavBase)` `} ${COMMON}; + ${sx}; ` SideNav.Link = styled(Link).attrs(props => { @@ -136,6 +138,8 @@ SideNav.Link = styled(Link).attrs(props => { font-weight: ${get('fontWeights.semibold')}; } } + + ${sx}; ` SideNav.defaultProps = { @@ -149,8 +153,7 @@ SideNav.propTypes = { children: PropTypes.node, theme: PropTypes.object, variant: PropTypes.oneOf(['normal', 'lightweight']), - ...BorderBox.propTypes, - ...COMMON.propTypes + ...BorderBox.propTypes } SideNav.Link.defaultProps = { @@ -166,4 +169,6 @@ SideNav.Link.propTypes = { ...Link.propTypes } +SideNav.Link.displayName = 'SideNav.Link' + export default SideNav diff --git a/src/StateLabel.js b/src/StateLabel.js index bd0bda8baae..84c996f0cd4 100644 --- a/src/StateLabel.js +++ b/src/StateLabel.js @@ -5,6 +5,7 @@ import {GitMerge, GitPullRequest, IssueClosed, IssueOpened} from '@primer/octico import theme, {colors} from './theme' import {COMMON, get} from './constants' import StyledOcticon from './StyledOcticon' +import sx from './sx' const statusMap = { issueClosed: colors.red[6], @@ -48,6 +49,7 @@ const StateLabel = styled(StateLabelBase)` background-color: ${props => (props.status ? statusMap[props.status] : statusMap.gray)}; border-radius: ${get('radii.3')}; ${COMMON}; + ${sx}; ` StateLabel.defaultProps = { @@ -58,7 +60,8 @@ StateLabel.propTypes = { small: PropTypes.bool, status: PropTypes.oneOf(['issueOpened', 'pullOpened', 'issueClosed', 'pullClosed', 'pullMerged']), theme: PropTypes.object, - ...COMMON.propTypes + ...COMMON.propTypes, + ...sx.propTypes } export default StateLabel diff --git a/src/StyledOcticon.js b/src/StyledOcticon.js index a07450ceeb9..4b3052bc983 100644 --- a/src/StyledOcticon.js +++ b/src/StyledOcticon.js @@ -3,8 +3,12 @@ import PropTypes from 'prop-types' import styled from 'styled-components' import {COMMON} from './constants' import theme from './theme' +import sx from './sx' -const StyledOcticon = styled(Octicon)(COMMON) +const StyledOcticon = styled(Octicon)` + ${COMMON}; + ${sx}; +` StyledOcticon.defaultProps = { theme @@ -12,6 +16,7 @@ StyledOcticon.defaultProps = { StyledOcticon.propTypes = { ...COMMON.propTypes, + ...sx.propTypes, theme: PropTypes.object } diff --git a/src/SubNav.js b/src/SubNav.js index 6b4ab9f16bd..6eeebd7b0cb 100644 --- a/src/SubNav.js +++ b/src/SubNav.js @@ -5,11 +5,12 @@ import styled from 'styled-components' import {COMMON, FLEX, get} from './constants' import theme from './theme' import Flex from './Flex' +import sx from './sx' const ITEM_CLASS = 'SubNav-item' const SELECTED_CLASS = 'selected' -function SubNavBase({actions, className, children, label, ...rest}) { +function SubNavBase({actions, className, children, label, theme, ...rest}) { const classes = classnames(className, 'SubNav') return (