From ee5b5a34928423a01db0f9cbc39b98e5da30403d Mon Sep 17 00:00:00 2001 From: Cole Bemis Date: Thu, 27 Jun 2019 13:09:32 -0700 Subject: [PATCH 01/39] Create Grid component --- pages/components/docs/Grid.md | 24 ++++ pages/components/docs/index.js | 1 + pages/components/docs/system-props.md | 4 +- src/Grid.js | 20 +++ src/__tests__/Grid.js | 78 +++++++++++ src/__tests__/__snapshots__/Grid.js.snap | 167 +++++++++++++++++++++++ src/constants.js | 2 + src/index.js | 1 + 8 files changed, 296 insertions(+), 1 deletion(-) create mode 100644 pages/components/docs/Grid.md create mode 100644 src/Grid.js create mode 100644 src/__tests__/Grid.js create mode 100644 src/__tests__/__snapshots__/Grid.js.snap diff --git a/pages/components/docs/Grid.md b/pages/components/docs/Grid.md new file mode 100644 index 00000000000..89b9d6d3862 --- /dev/null +++ b/pages/components/docs/Grid.md @@ -0,0 +1,24 @@ +# Grid + +Grid is a component that exposes grid system props. See the [CSS Tricks Complete Guide to Grid](https://css-tricks.com/snippets/css/complete-guide-grid/) to learn more about Grid Layout. + +## Default example + +```.jsx + + 1 + 2 + +``` + +## System props + +Grid components get `GRID`, `COMMON`, and `LAYOUT` system props. + +Read our [System Props](/components/docs/system-props) doc page for a full list of available props. + +## Component props + +`Grid` does not get any additional props other than the system props mentioned above. + +export const meta = {displayName: 'Grid'} diff --git a/pages/components/docs/index.js b/pages/components/docs/index.js index 13bc6658bfd..74646f08711 100644 --- a/pages/components/docs/index.js +++ b/pages/components/docs/index.js @@ -11,6 +11,7 @@ export {meta as Dropdown} from './Dropdown.md' export {meta as FilterList} from './FilterList.md' export {meta as Flash} from './Flash.md' export {meta as Flex} from './Flex.md' +export {meta as Grid} from './Grid.md' export {meta as Heading} from './Heading.md' export {meta as Label} from './Label.md' export {meta as Link} from './Link.md' diff --git a/pages/components/docs/system-props.md b/pages/components/docs/system-props.md index be661da1d73..36ee6d28b4e 100644 --- a/pages/components/docs/system-props.md +++ b/pages/components/docs/system-props.md @@ -1,4 +1,4 @@ -import {COMMON, LAYOUT, BORDER, TYPOGRAPHY, FLEX, POSITION} from '../../../src/constants.js' +import {COMMON, LAYOUT, BORDER, TYPOGRAPHY, FLEX, POSITION, GRID} from '../../../src/constants.js' import {PropsList} from '../../doc-components' # System Props @@ -20,3 +20,5 @@ To check which system props each component includes, check the documentation for | `LAYOUT` | | [styled-system layout docs](https://github.com/jxnblk/styled-system/blob/master/docs/table.md#layout)
[styled-system misc docs](https://github.com/jxnblk/styled-system/blob/master/docs/table.md#misc) | | `POSITION` | | [styled-system position docs](https://github.com/jxnblk/styled-system/blob/master/docs/table.md#position) | `FLEX` | | [styled-system flexbox docs](https://github.com/jxnblk/styled-system/blob/master/docs/table.md#flexbox) | +| `GRID` | | [styled-system grid docs](https://github.com/styled-system/styled-system/blob/master/docs/table.md#grid-layout) | + diff --git a/src/Grid.js b/src/Grid.js new file mode 100644 index 00000000000..c023334ab0e --- /dev/null +++ b/src/Grid.js @@ -0,0 +1,20 @@ +import styled from 'styled-components' +import {GRID} from './constants' +import theme from './theme' +import Box from './Box' + +const Grid = styled(Box)` + ${GRID}; +` + +Grid.defaultProps = { + theme, + display: 'grid' +} + +Grid.propTypes = { + ...Box.propTypes, + ...GRID.propTypes +} + +export default Grid diff --git a/src/__tests__/Grid.js b/src/__tests__/Grid.js new file mode 100644 index 00000000000..fff561b3db2 --- /dev/null +++ b/src/__tests__/Grid.js @@ -0,0 +1,78 @@ +import React from 'react' +import Grid from '../Grid' +import {GRID} from '../constants' +import {render} from '../utils/testing' + +describe('Grid', () => { + it('implements system props', () => { + expect(Grid).toImplementSystemProps(GRID) + }) + + it('has default theme', () => { + expect(Grid).toSetDefaultTheme() + }) + + it('gets display: grid by default', () => { + expect(render()).toHaveStyleRule('display', 'grid') + }) + + it('respects gridGap', () => { + expect(render()).toMatchSnapshot() + }) + + it('respects gridColumnGap', () => { + expect(render()).toMatchSnapshot() + }) + + it('respects gridRowGap', () => { + expect(render()).toMatchSnapshot() + }) + + it('respects gridColumn', () => { + expect(render()).toMatchSnapshot() + }) + + it('respects gridRow', () => { + expect(render()).toMatchSnapshot() + }) + + it('respects gridArea', () => { + expect(render()).toMatchSnapshot() + }) + + it('respects gridAutoFlow', () => { + expect(render()).toMatchSnapshot() + }) + + it('respects gridAutoRows', () => { + expect(render()).toMatchSnapshot() + }) + + it('respects gridAutoColumns', () => { + expect(render()).toMatchSnapshot() + }) + + it('respects gridTemplateColumns', () => { + expect(render()).toMatchSnapshot() + }) + + it('respects gridTemplateRows', () => { + expect(render()).toMatchSnapshot() + }) + + it('respects gridTemplateAreas', () => { + expect(render()).toMatchSnapshot() + }) + + it('respects responsive display', () => { + expect(render()).toMatchSnapshot() + }) + + it('respects the "as" prop', () => { + expect(render().type).toEqual('span') + }) + + it('renders a div by default', () => { + expect(render().type).toEqual('div') + }) +}) diff --git a/src/__tests__/__snapshots__/Grid.js.snap b/src/__tests__/__snapshots__/Grid.js.snap new file mode 100644 index 00000000000..5bd262c9edb --- /dev/null +++ b/src/__tests__/__snapshots__/Grid.js.snap @@ -0,0 +1,167 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Grid respects gridArea 1`] = ` +.c0 { + display: grid; + grid-area: sidebar; +} + +
+`; + +exports[`Grid respects gridAutoColumns 1`] = ` +.c0 { + display: grid; + grid-auto-columns: 1fr; +} + +
+`; + +exports[`Grid respects gridAutoFlow 1`] = ` +.c0 { + display: grid; + grid-auto-flow: row; +} + +
+`; + +exports[`Grid respects gridAutoRows 1`] = ` +.c0 { + display: grid; + grid-auto-rows: 1fr; +} + +
+`; + +exports[`Grid respects gridColumn 1`] = ` +.c0 { + display: grid; + grid-column: 1 / 2; +} + +
+`; + +exports[`Grid respects gridColumnGap 1`] = ` +.c0 { + display: grid; + grid-column-gap: 8px; +} + +
+`; + +exports[`Grid respects gridGap 1`] = ` +.c0 { + display: grid; + grid-gap: 4px; +} + +
+`; + +exports[`Grid respects gridRow 1`] = ` +.c0 { + display: grid; + grid-row: 1 / 2; +} + +
+`; + +exports[`Grid respects gridRowGap 1`] = ` +.c0 { + display: grid; + grid-row-gap: 8px; +} + +
+`; + +exports[`Grid respects gridTemplateAreas 1`] = ` +.c0 { + display: grid; + grid-template-areas: sidebar main; +} + +
+`; + +exports[`Grid respects gridTemplateColumns 1`] = ` +.c0 { + display: grid; + grid-template-columns: 200px 1fr; +} + +
+`; + +exports[`Grid respects gridTemplateRows 1`] = ` +.c0 { + display: grid; + grid-template-rows: 200px 1fr; +} + +
+`; + +exports[`Grid respects responsive display 1`] = ` +.c0 { + display: grid; +} + +@media screen and (min-width:544px) { + .c0 { + display: inline-grid; + } +} + +
+`; diff --git a/src/constants.js b/src/constants.js index 5c60e4a79a4..bb4e44eb060 100644 --- a/src/constants.js +++ b/src/constants.js @@ -31,8 +31,10 @@ export const TYPOGRAPHY = styledSystem.typography export const LAYOUT = styledSystem.layout export const POSITION = styledSystem.position export const FLEX = styledSystem.flexbox +export const GRID = styledSystem.grid TYPOGRAPHY.propTypes = systemPropTypes.typography LAYOUT.propTypes = systemPropTypes.layout POSITION.propTypes = systemPropTypes.position FLEX.propTypes = systemPropTypes.flexbox +GRID.propTypes = systemPropTypes.grid diff --git a/src/index.js b/src/index.js index 4745e5965e4..c04b0abea80 100644 --- a/src/index.js +++ b/src/index.js @@ -5,6 +5,7 @@ export {default as BaseStyles} from './BaseStyles' export {default as BorderBox} from './BorderBox' export {default as Box} from './Box' export {default as Flex} from './Flex' +export {default as Grid} from './Grid' export {Position, Absolute, Fixed, Relative, Sticky} from './Position' // Components From 06ed3b25a9217ece7907935ef2fcadbe5c68d8d1 Mon Sep 17 00:00:00 2001 From: Cole Bemis Date: Thu, 27 Jun 2019 13:31:51 -0700 Subject: [PATCH 02/39] Bump version to 13.2.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5b28d9871f5..54999e9fcd3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@primer/components", - "version": "13.1.0", + "version": "13.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 362f3e7d053..f7f76be4b75 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@primer/components", - "version": "13.1.0", + "version": "13.2.0", "description": "Primer react components", "main": "dist/index.umd.js", "module": "dist/index.esm.js", From e1941a6455cff6a23ec28760c95dc95dbc160394 Mon Sep 17 00:00:00 2001 From: Cole Bemis Date: Fri, 28 Jun 2019 09:57:37 -0700 Subject: [PATCH 03/39] Fix typo in Link so it applies button styles --- src/Link.js | 2 +- src/__tests__/Link.js | 4 +++ src/__tests__/__snapshots__/Link.js.snap | 32 ++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/Link.js b/src/Link.js index c086914faec..dc030fe652a 100644 --- a/src/Link.js +++ b/src/Link.js @@ -29,7 +29,7 @@ const Link = styled.a` text-decoration: underline; ${hoverColor}; } - ${props => (props.is === 'button' ? buttonStyles : '')}; + ${props => (props.as === 'button' ? buttonStyles : '')}; ${TYPOGRAPHY} ${COMMON}; ` diff --git a/src/__tests__/Link.js b/src/__tests__/Link.js index fe88b342b40..f247e681bd2 100644 --- a/src/__tests__/Link.js +++ b/src/__tests__/Link.js @@ -34,4 +34,8 @@ describe('Link', () => { expect(render()).toHaveStyleRule('font-style', 'italic') expect(render()).toHaveStyleRule('font-style', 'normal') }) + + it('applies button styles when rendering a button element', () => { + expect(render()).toMatchSnapshot() + }) }) diff --git a/src/__tests__/__snapshots__/Link.js.snap b/src/__tests__/__snapshots__/Link.js.snap index 642911e0b2a..db6af044eae 100644 --- a/src/__tests__/__snapshots__/Link.js.snap +++ b/src/__tests__/__snapshots__/Link.js.snap @@ -1,5 +1,37 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Link applies button styles when rendering a button element 1`] = ` +.c0 { + -webkit-text-decoration: none; + text-decoration: none; + display: inline-block; + padding: 0; + font-size: inherit; + white-space: nowrap; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-color: transparent; + border: 0; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + color: #0366d6; +} + +.c0:hover { + -webkit-text-decoration: underline; + text-decoration: underline; +} + + + setIsOpen(false)}> + + Some content + + + + )} + ``` ## System props diff --git a/pages/doc-components/State.js b/pages/doc-components/State.js new file mode 100644 index 00000000000..b5d7c496ac7 --- /dev/null +++ b/pages/doc-components/State.js @@ -0,0 +1,9 @@ +import React from 'react' + +const State = props => { + const result = React.useState(props.default) + + return props.children(result) +} + +export default State diff --git a/src/Dialog.js b/src/Dialog.js index cd60c4e7ab5..c2377899710 100644 --- a/src/Dialog.js +++ b/src/Dialog.js @@ -1,7 +1,7 @@ import React from 'react' import {Dialog as ReachDialog} from '@reach/dialog' import reachStyles from '@reach/dialog/styles.css' -import styled from 'styled-components' +import styled, {createGlobalStyle} from 'styled-components' import PropTypes from 'prop-types' import {space, color} from 'styled-system' import systemPropTypes from '@styled-system/prop-types' @@ -12,8 +12,11 @@ import theme from './theme' import Text from './Text' import Flex from './Flex' -export const Dialog = styled(ReachDialog)` +const ReachGlobalStyle = createGlobalStyle` ${reachStyles} +` + +export const Dialog = styled(ReachDialog)` box-shadow: 0px 4px 32px rgba(0, 0, 0, 0.35); border-radius: 4px; padding: 0 !important; @@ -49,26 +52,29 @@ Dialog.propTypes = { const DialogWithHeader = ({title, children, ...props}) => { return ( - - - - {title} - - - - - - {children} - + <> + + + + {title} + + + + + + {children} + + + ) } From 1a97e9eefd14bd58bd3ed948b22ed71aaf5cd089 Mon Sep 17 00:00:00 2001 From: Max Stoiber Date: Mon, 1 Jul 2019 11:05:26 +0200 Subject: [PATCH 08/39] Fix the z-index of the Dialog --- src/Dialog.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Dialog.js b/src/Dialog.js index c2377899710..8afc68f6cad 100644 --- a/src/Dialog.js +++ b/src/Dialog.js @@ -14,6 +14,10 @@ import Flex from './Flex' const ReachGlobalStyle = createGlobalStyle` ${reachStyles} + + [data-reach-dialog-overlay] { + z-index: 1000002; /* Higher than the Dropdown and Tooltip */ + } ` export const Dialog = styled(ReachDialog)` From 397e56b5fa65aff410b5d1e8966ed3174be1cfb7 Mon Sep 17 00:00:00 2001 From: Max Stoiber Date: Mon, 1 Jul 2019 11:09:42 +0200 Subject: [PATCH 09/39] Extract DialogHeader component --- src/Dialog.js | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/Dialog.js b/src/Dialog.js index 8afc68f6cad..ef130947918 100644 --- a/src/Dialog.js +++ b/src/Dialog.js @@ -45,6 +45,20 @@ const UnstyledButton = styled(Flex).attrs({ padding: none; ` +const DialogHeader = styled(Flex).attrs({ + p: 3, + bg: 'gray.1', + justifyContent: 'space-between', + alignItems: 'center' +})` + border-radius: 4px 4px 0px 0px; + border-bottom: 1px solid #dad5da; + + @media screen and (max-width: 750px) { + border-radius: 0px; + } +` + Dialog.defaultProps = {theme} Dialog.propTypes = { @@ -58,23 +72,14 @@ const DialogWithHeader = ({title, children, ...props}) => { return ( <> - + {title} - + {children} From 2983c935ea9ad600c04078adb25e40c3624c11fa Mon Sep 17 00:00:00 2001 From: Max Stoiber Date: Mon, 1 Jul 2019 12:36:10 +0200 Subject: [PATCH 10/39] Add first TypeScript types --- index.d.ts | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 + 2 files changed, 206 insertions(+) create mode 100644 index.d.ts diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 00000000000..d82e82ccad9 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,204 @@ +declare module '@primer/components' { + type Omit = Pick> + import * as StyledSystem from 'styled-system' + import * as StyledComponents from 'styled-components' + import * as History from 'history' + + export interface BaseProps extends React.Props { + as?: React.ReactType + title?: string + // NOTE(@mxstbr): Necessary workaround to make work + to?: History.LocationDescriptor + } + + interface CommonProps extends BaseProps, StyledSystem.ColorProps, StyledSystem.SpaceProps {} + + interface LayoutProps + extends BaseProps, + StyledSystem.DisplayProps, + StyledSystem.SizeProps, + StyledSystem.WidthProps, + StyledSystem.HeightProps, + StyledSystem.MinWidthProps, + StyledSystem.MinHeightProps, + StyledSystem.MaxWidthProps, + StyledSystem.MaxHeightProps, + StyledSystem.OverflowProps, + StyledSystem.VerticalAlignProps {} + + interface TypographyProps + extends BaseProps, + StyledSystem.FontFamilyProps, + StyledSystem.FontSizeProps, + StyledSystem.FontStyleProps, + StyledSystem.FontWeightProps, + StyledSystem.LineHeightProps, + StyledSystem.TextAlignProps {} + + interface BorderProps + extends BaseProps, + StyledSystem.BordersProps, + StyledSystem.BorderColorProps, + StyledSystem.BoxShadowProps, + StyledSystem.BorderRadiusProps {} + + interface PositionProps + extends BaseProps, + StyledSystem.PositionProps, + StyledSystem.ZIndexProps, + StyledSystem.TopProps, + StyledSystem.RightProps, + StyledSystem.BottomProps, + StyledSystem.LeftProps {} + + interface FlexContainerProps + extends BaseProps, + CommonProps, + LayoutProps, + StyledSystem.FlexBasisProps, + StyledSystem.FlexDirectionProps, + StyledSystem.FlexWrapProps, + StyledSystem.AlignContentProps, + StyledSystem.AlignItemsProps, + StyledSystem.JustifyContentProps, + StyledSystem.JustifyItemsProps {} + + interface FlexItemProps + extends BaseProps, + CommonProps, + LayoutProps, + StyledSystem.FlexProps, + StyledSystem.JustifySelfProps, + StyledSystem.AlignSelfProps, + StyledSystem.OrderProps {} + + export interface FlexProps + extends FlexContainerProps, + Omit, keyof FlexContainerProps> {} + + export interface BoxProps extends BaseProps, CommonProps, LayoutProps {} + + export interface TextProps extends BaseProps, CommonProps, TypographyProps {} + export interface HeadingProps extends BaseProps, CommonProps, TypographyProps {} + + type DetailsRenderFunction = (args: {open: boolean; toggle: () => void}) => React.ReactElement + + export interface DetailsProps extends CommonProps { + open?: boolean + render?: DetailsRenderFunction + children?: DetailsRenderFunction | React.ReactNode + overlay?: boolean + } + + export interface ButtonProps extends BaseProps, CommonProps { + disabled?: boolean + grouped?: boolean + onClick?: Function + size?: 'sm' | 'large' + } +} + +declare module '@primer/components/src/Box' { + import {BoxProps} from '@primer/components' + + export {BoxProps} + + const Box: React.FunctionComponent + + export default Box +} + +declare module '@primer/components/src/Text' { + import {TextProps} from '@primer/components' + + const Text: React.FunctionComponent + + export default Text +} + +declare module '@primer/components/src/Heading' { + import {HeadingProps} from '@primer/components' + + const Heading: React.FunctionComponent + + export default Heading +} + +declare module '@primer/components/src/ButtonDanger' { + import {ButtonProps} from '@primer/components' + + const ButtonDanger: React.FunctionComponent + + export default ButtonDanger +} + +declare module '@primer/components/src/ButtonPrimary' { + import {ButtonProps} from '@primer/components' + + const ButtonPrimary: React.FunctionComponent + + export default ButtonPrimary +} + +declare module '@primer/components/src/ButtonOutline' { + import {ButtonProps} from '@primer/components' + + const ButtonOutline: React.FunctionComponent + + export default ButtonOutline +} + +declare module '@primer/components/src/Button' { + import {ButtonProps} from '@primer/components' + + const Button: React.FunctionComponent + + export default Button +} + +declare module '@primer/components/src/Flex' { + import {FlexProps, FlexItemProps} from '@primer/components' + + const Flex: React.FunctionComponent & { + Item: React.FunctionComponent + } + + export {FlexProps, FlexItemProps} + + export default Flex +} + +declare module '@primer/components/src/Avatar' { + import {CommonProps} from '@primer/components' + + const Avatar: React.FunctionComponent< + CommonProps & { + alt: string + src: string + isChild?: boolean + size?: number + } + > + + export default Avatar +} + +declare module '@primer/components/src/Details' { + import {DetailsProps} from '@primer/components' + + const Details: React.FunctionComponent + + export default Details +} + +declare module '@primer/components/src/BaseStyles' { + import {TypographyProps, CommonProps} from '@primer/components' + + const BaseStyles: React.FunctionComponent + + export default BaseStyles +} + +declare module '@primer/components/src/theme' { + export default Object +} diff --git a/package.json b/package.json index 362f3e7d053..0929997e80f 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Primer react components", "main": "dist/index.umd.js", "module": "dist/index.esm.js", + "typings": "index.d.ts", "scripts": { "dev": "next dev", "prebuild": "npm run dist", @@ -31,6 +32,7 @@ "codemods", "dist", "src", + "index.d.ts", "!src/__tests__", "!src/utils" ], From fb7daf1edd30e3f14479f9b096a59e4f3da53375 Mon Sep 17 00:00:00 2001 From: Max Stoiber Date: Mon, 1 Jul 2019 12:41:09 +0200 Subject: [PATCH 11/39] Remove incorrect theme types --- index.d.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/index.d.ts b/index.d.ts index d82e82ccad9..b7e6b7da9a6 100644 --- a/index.d.ts +++ b/index.d.ts @@ -199,6 +199,3 @@ declare module '@primer/components/src/BaseStyles' { export default BaseStyles } -declare module '@primer/components/src/theme' { - export default Object -} From 8379109896c3d081f54e00e9122ad2411776b6a1 Mon Sep 17 00:00:00 2001 From: Max Stoiber Date: Mon, 1 Jul 2019 14:20:43 +0200 Subject: [PATCH 12/39] Export components from main bundle --- index.d.ts | 97 +++++++++++++++++++++++------------------------------- 1 file changed, 41 insertions(+), 56 deletions(-) diff --git a/index.d.ts b/index.d.ts index b7e6b7da9a6..172598a3305 100644 --- a/index.d.ts +++ b/index.d.ts @@ -76,11 +76,22 @@ declare module '@primer/components' { extends FlexContainerProps, Omit, keyof FlexContainerProps> {} + export const Flex: React.FunctionComponent & { + Item: React.FunctionComponent + } + export interface BoxProps extends BaseProps, CommonProps, LayoutProps {} + export const Box: React.FunctionComponent + export interface TextProps extends BaseProps, CommonProps, TypographyProps {} + + export const Text: React.FunctionComponent + export interface HeadingProps extends BaseProps, CommonProps, TypographyProps {} + export const Heading: React.FunctionComponent + type DetailsRenderFunction = (args: {open: boolean; toggle: () => void}) => React.ReactElement export interface DetailsProps extends CommonProps { @@ -90,112 +101,86 @@ declare module '@primer/components' { overlay?: boolean } + export const Details: React.FunctionComponent + export interface ButtonProps extends BaseProps, CommonProps { disabled?: boolean grouped?: boolean onClick?: Function size?: 'sm' | 'large' } -} -declare module '@primer/components/src/Box' { - import {BoxProps} from '@primer/components' + export const ButtonPrimary: React.FunctionComponent + export const ButtonOutline: React.FunctionComponent + export const ButtonDanger: React.FunctionComponent + export const Button: React.FunctionComponent - export {BoxProps} + export interface AvatarProps extends CommonProps { + alt: string + src: string + isChild?: boolean + size?: number + } + + export const Avatar: React.FunctionComponent - const Box: React.FunctionComponent + export interface BaseStylesProps extends TypographyProps, CommonProps {} + export const BaseStyles: React.FunctionComponent +} + +declare module '@primer/components/src/Box' { + import {Box} from '@primer/components' export default Box } declare module '@primer/components/src/Text' { - import {TextProps} from '@primer/components' - - const Text: React.FunctionComponent - + import {Text} from '@primer/components' export default Text } declare module '@primer/components/src/Heading' { - import {HeadingProps} from '@primer/components' - - const Heading: React.FunctionComponent - + import {Heading} from '@primer/components' export default Heading } declare module '@primer/components/src/ButtonDanger' { - import {ButtonProps} from '@primer/components' - - const ButtonDanger: React.FunctionComponent - + import {ButtonDanger} from '@primer/components' export default ButtonDanger } declare module '@primer/components/src/ButtonPrimary' { - import {ButtonProps} from '@primer/components' - - const ButtonPrimary: React.FunctionComponent - + import {ButtonPrimary} from '@primer/components' export default ButtonPrimary } declare module '@primer/components/src/ButtonOutline' { - import {ButtonProps} from '@primer/components' - - const ButtonOutline: React.FunctionComponent - + import {ButtonOutline} from '@primer/components' export default ButtonOutline } declare module '@primer/components/src/Button' { - import {ButtonProps} from '@primer/components' - - const Button: React.FunctionComponent - + import {Button} from '@primer/components' export default Button } declare module '@primer/components/src/Flex' { - import {FlexProps, FlexItemProps} from '@primer/components' - - const Flex: React.FunctionComponent & { - Item: React.FunctionComponent - } - - export {FlexProps, FlexItemProps} - + import {Flex} from '@primer/components' export default Flex } declare module '@primer/components/src/Avatar' { - import {CommonProps} from '@primer/components' - - const Avatar: React.FunctionComponent< - CommonProps & { - alt: string - src: string - isChild?: boolean - size?: number - } - > - + import {Avatar} from '@primer/components' export default Avatar } declare module '@primer/components/src/Details' { - import {DetailsProps} from '@primer/components' - - const Details: React.FunctionComponent - + import {Details} from '@primer/components' export default Details } declare module '@primer/components/src/BaseStyles' { - import {TypographyProps, CommonProps} from '@primer/components' - - const BaseStyles: React.FunctionComponent - + import {BaseStyles} from '@primer/components' export default BaseStyles } From 2d722646116d24a925f8d1151b50c29a7a339be5 Mon Sep 17 00:00:00 2001 From: Cole Bemis Date: Tue, 2 Jul 2019 12:27:23 -0700 Subject: [PATCH 13/39] Export get as themeGet --- src/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.js b/src/index.js index 4745e5965e4..15493c6527d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,5 @@ export {default as theme} from './theme' +export {get as themeGet} from './constants' export {default as BaseStyles} from './BaseStyles' // Layout From eae62e36672f76770e7ee1bb4b8f5ba97651216f Mon Sep 17 00:00:00 2001 From: Cole Bemis Date: Tue, 2 Jul 2019 12:28:26 -0700 Subject: [PATCH 14/39] Add themeGet tests --- src/__tests__/themeGet.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/__tests__/themeGet.js diff --git a/src/__tests__/themeGet.js b/src/__tests__/themeGet.js new file mode 100644 index 00000000000..48a18d23381 --- /dev/null +++ b/src/__tests__/themeGet.js @@ -0,0 +1,16 @@ +import {themeGet} from '..' + +describe('themeGet', () => { + it('acccepts theme prop', () => { + expect(themeGet('example')({theme: {example: 'test'}})).toBe('test') + }) + + it('allows theme prop to override primer theme', () => { + expect(themeGet('colors.gray.0')({theme: {colors: {gray: ['#f00']}}})).toBe('#f00') + }) + + it('uses primer theme as fallback', () => { + expect(themeGet('colors.gray.1')({})).toBe('#f6f8fa') + expect(themeGet('colors.gray.1')({theme: {colors: {foo: 'bar'}}})).toBe('#f6f8fa') + }) +}) From 1833fa3ce8d8ee7fc4f7bef6bd0acbfee997bf45 Mon Sep 17 00:00:00 2001 From: Max Stoiber Date: Wed, 3 Jul 2019 11:38:13 +0200 Subject: [PATCH 15/39] Add more types --- index.d.ts | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/index.d.ts b/index.d.ts index 172598a3305..09c97f88158 100644 --- a/index.d.ts +++ b/index.d.ts @@ -127,6 +127,73 @@ declare module '@primer/components' { export interface BaseStylesProps extends TypographyProps, CommonProps {} export const BaseStyles: React.FunctionComponent + + export interface BorderBoxProps extends CommonProps, LayoutProps { + border?: string + borderColor?: string + borderRadius?: string | number + boxShadow?: string + } + + export const BorderBox: React.FunctionComponent + + export interface BranchNameProps extends CommonProps { + href?: string + } + + export const BranchName: React.FunctionComponent + + export interface CircleBadgeProps extends CommonProps { + size?: string | number + } + + export const CircleBadge: React.FunctionComponent + + export interface CircleOcticonProps extends CommonProps { + size?: number + icon: React.ReactNode + } + + export const CircleOcticon: React.FunctionComponent + + export interface StyledOcticonProps extends CommonProps { + size?: number + icon: React.ReactNode + } + + export const StyledOcticon: React.FunctionComponent + + export interface DropdownProps extends CommonProps {} + + export interface DropdownMenuProps extends CommonProps { + direction?: string + title: string + } + + export const Dropdown: React.FunctionComponent & { + Menu: React.FunctionComponent + Item: React.FunctionComponent + } + + export interface FilterListProps extends CommonProps { + small?: boolean + } + + export interface FilterListItemProps extends CommonProps { + count?: number + selected?: boolean + } + + export const FilterList: React.FunctionComponent & { + Item: React.FunctionComponent + } + + export interface FlashProps extends CommonProps { + full?: boolean + scheme?: string + } + + export const Flash: React.FunctionComponent } declare module '@primer/components/src/Box' { @@ -184,3 +251,36 @@ declare module '@primer/components/src/BaseStyles' { export default BaseStyles } +declare module '@primer/components/src/BorderBox' { + import {BorderBox} from '@primer/components' + export default BorderBox +} + +declare module '@primer/components/src/BranchName' { + import {BranchName} from '@primer/components' + export default BranchName +} +declare module '@primer/components/src/CircleBadge' { + import {CircleBadge} from '@primer/components' + export default CircleBadge +} +declare module '@primer/components/src/CircleOcticon' { + import {CircleOcticon} from '@primer/components' + export default CircleOcticon +} +declare module '@primer/components/src/StyledOcticon' { + import {StyledOcticon} from '@primer/components' + export default StyledOcticon +} +declare module '@primer/components/src/Dropdown' { + import {Dropdown} from '@primer/components' + export default Dropdown +} +declare module '@primer/components/src/FilterList' { + import {FilterList} from '@primer/components' + export default FilterList +} +declare module '@primer/components/src/Flash' { + import {Flash} from '@primer/components' + export default Flash +} From 17883d77e54b7fe5bf4060c439724f907eea7c1f Mon Sep 17 00:00:00 2001 From: Max Stoiber Date: Wed, 3 Jul 2019 11:57:06 +0200 Subject: [PATCH 16/39] Finish typing all components --- index.d.ts | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/index.d.ts b/index.d.ts index 09c97f88158..013475d8a62 100644 --- a/index.d.ts +++ b/index.d.ts @@ -194,6 +194,84 @@ declare module '@primer/components' { } export const Flash: React.FunctionComponent + + export interface CounterLabelProps extends CommonProps { + scheme?: string + } + + export const CounterLabel: React.FunctionComponent + + export interface LabelProps extends CommonProps { + outline?: boolean + size?: 'small' | 'medium' | 'large' | 'xl' + dropshadow?: boolean + } + + export const Label: React.FunctionComponent + + export interface LinkProps extends CommonProps, TypographyProps { + href: string + underline?: boolean + } + + export const Link: React.FunctionComponent + + export interface PointerBoxProps extends CommonProps, LayoutProps { + caret?: string + } + + export const PointerBox: React.FunctionComponent + + export interface PositionComponentProps extends PositionProps, CommonProps, LayoutProps {} + + export const Relative: React.FunctionComponent + export const Absolute: React.FunctionComponent + export const Sticky: React.FunctionComponent + export const Fixed: React.FunctionComponent + + export interface StateLabelProps extends CommonProps { + small?: boolean + status: 'issueOpened' | 'issueClosed' | 'pullOpened' | 'pullClosed' | 'pullMerged' + } + + export const StateLabel: React.FunctionComponent + + export interface TextInputProps extends CommonProps { + autocomplete?: string + 'aria-label'?: string + block?: boolean + disabled?: boolean + id?: string + name?: string + onChange?: (evt: React.ChangeEvent) => void + placeholder?: string + required?: boolean + size?: 'small' | 'large' + value?: string + } + + export const TextInput: React.FunctionComponent + + export interface TooltipProps extends CommonProps { + align?: 'left' | 'right' + direction?: 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw' + noDelay?: boolean + text?: string + wrap?: boolean + } + + export const Tooltip: React.FunctionComponent + + export interface UnderlineNavProps extends CommonProps { + actions?: React.ReactNode + align?: 'right' + full?: boolean + label?: string + } + + export const UnderlineNav: React.FunctionComponent + + export const theme: Object } declare module '@primer/components/src/Box' { @@ -284,3 +362,58 @@ declare module '@primer/components/src/Flash' { import {Flash} from '@primer/components' export default Flash } + +declare module '@primer/components/src/CounterLabel' { + import {CounterLabel} from '@primer/components' + export default CounterLabel +} + +declare module '@primer/components/src/Label' { + import {Label} from '@primer/components' + export default Label +} + +declare module '@primer/components/src/Link' { + import {Link} from '@primer/components' + export default Link +} +declare module '@primer/components/src/PointerBox' { + import {PointerBox} from '@primer/components' + export default PointerBox +} +declare module '@primer/components/src/Relative' { + import {Relative} from '@primer/components' + export default Relative +} +declare module '@primer/components/src/Absolute' { + import {Absolute} from '@primer/components' + export default Absolute +} +declare module '@primer/components/src/Sticky' { + import {Sticky} from '@primer/components' + export default Sticky +} +declare module '@primer/components/src/Fixed' { + import {Fixed} from '@primer/components' + export default Fixed +} +declare module '@primer/components/src/StateLabel' { + import {StateLabel} from '@primer/components' + export default StateLabel +} +declare module '@primer/components/src/TextInput' { + import {TextInput} from '@primer/components' + export default TextInput +} +declare module '@primer/components/src/Tooltip' { + import {Tooltip} from '@primer/components' + export default Tooltip +} +declare module '@primer/components/src/UnderlineNav' { + import {UnderlineNav} from '@primer/components' + export default UnderlineNav +} +declare module '@primer/components/src/theme' { + import {theme} from '@primer/components' + export default theme +} From 88731cdaf06f26dfa0f25a22e476647bb52aac7a Mon Sep 17 00:00:00 2001 From: Max Stoiber Date: Wed, 3 Jul 2019 12:16:28 +0200 Subject: [PATCH 17/39] Add TypeScript def check to merge checklist --- .github/pull_request_template.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 4474399e898..c11db0e4db7 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -9,6 +9,7 @@ Description of changes #### Merge checklist - [ ] Changed base branch to release branch +- [ ] Add or update TypeScript definitions (`index.d.ts`) if necessary - [ ] Tested in Chrome - [ ] Tested in Firefox - [ ] Tested in Safari From 10f9bc72de38e50728afe277441e8e6903bd5d20 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 3 Jul 2019 08:42:04 -0700 Subject: [PATCH 18/39] add Button Group --- pages/components/docs/Button.md | 6 +++++ src/Button.js | 23 ++++++++++++++++++- src/ButtonStyles.js | 39 +++++++++++++++++++++++++++------ 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/pages/components/docs/Button.md b/pages/components/docs/Button.md index e7cda4801b7..b24f4bde6c2 100644 --- a/pages/components/docs/Button.md +++ b/pages/components/docs/Button.md @@ -12,6 +12,12 @@ In special cases where you'd like to use a `` styled like a Button, use `Button Danger Button Outline Button Primary + + + + + + ``` ## System props diff --git a/src/Button.js b/src/Button.js index d9dd60a2648..a8303b76447 100644 --- a/src/Button.js +++ b/src/Button.js @@ -3,6 +3,7 @@ import styled from 'styled-components' import {COMMON, get} from './constants' import theme from './theme' import getButtonStyles from './ButtonStyles' +import Box from './Box' import {layout} from 'styled-system' import systemPropTypes from '@styled-system/prop-types' @@ -13,9 +14,20 @@ function fontSize({size = '14px', ...props}) { } } +const getClasses = (props) => { + const classes = [] + if (props.disabled){ + classes.push('disabled') + } + if (props.grouped) { + classes.push('grouped') + } + return classes.join(' ') +} + const Button = styled.button.attrs(props => ({ onClick: props.disabled ? undefined : props.onClick, - className: props.disabled ? 'disabled' : '' + className: getClasses(props) }))` ${props => (props.theme ? getButtonStyles(props.theme) : '')}; ${fontSize}; @@ -27,6 +39,15 @@ Button.defaultProps = { theme } +const Group = ({children, ...rest}) => { + const newChildren = React.Children.map(children, child => React.cloneElement(child, { grouped: true })) + return ( + {newChildren} + ) +} + +Button.Group = Group + Button.propTypes = { as: PropTypes.oneOfType([PropTypes.oneOf(['button', 'a', 'summary', 'input']), PropTypes.func]), children: PropTypes.node, diff --git a/src/ButtonStyles.js b/src/ButtonStyles.js index 4dc05971bb8..09da6606198 100644 --- a/src/ButtonStyles.js +++ b/src/ButtonStyles.js @@ -42,25 +42,50 @@ const getButtonStyles = theme => { border-color: ${get('colors.button.border')(theme)}; //convert black to rbg here } - &:selected { - background-color: ${get('colors.button.activeBg')(theme)}; - background-image: none; - box-shadow: ${get('colors.blackfade15')(theme)} 0px 0.15em 0.3em inset; - border-color: ${get('colors.button.border')(theme)}; - } - &.disabled { color: ${get('colors.button.disabledColor')(theme)}!important; background-color: ${get('colors.gray.1')(theme)}!important; background-image: none!important; border-color: ${get('colors.blackfade20')(theme)}!important; box-shadow: none!important; + cursor: default; } &:focus { outline: none; box-shadow: ${get('colors.button.focusShadow')(theme)} 0px 0px 0px 0.2em; } + + &.grouped { + position: relative; + border-right-width: 0; + border-radius: 0; + + &:first-child { + border-top-left-radius: ${get('radii.1')(theme)}px; + border-bottom-left-radius: ${get('radii.1')(theme)}px; + } + + &:last-child { + border-right-width: 1px; + border-top-right-radius: ${get('radii.1')(theme)}px; + border-bottom-right-radius: ${get('radii.1')(theme)}px; + } + + &:focus, + &:active, + &:hover { + border-right-width: 1px; + + + .grouped { + border-left-width: 0; + } + } + } + &:focus, + &:active { + z-index: 1; + } ` } From 3051ede8b13dcb518771794065d82c9dea4c50a1 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 3 Jul 2019 08:45:15 -0700 Subject: [PATCH 19/39] update docs --- pages/components/docs/Button.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pages/components/docs/Button.md b/pages/components/docs/Button.md index b24f4bde6c2..44e80b0882b 100644 --- a/pages/components/docs/Button.md +++ b/pages/components/docs/Button.md @@ -5,6 +5,8 @@ In special cases where you'd like to use a `` styled like a Button, use ` @@ -22,10 +24,11 @@ In special cases where you'd like to use a `` styled like a Button, use ` Date: Wed, 3 Jul 2019 08:57:39 -0700 Subject: [PATCH 20/39] adds tests --- src/Button.js | 4 ++++ src/__tests__/Button.js | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/Button.js b/src/Button.js index a8303b76447..812dc8b12eb 100644 --- a/src/Button.js +++ b/src/Button.js @@ -48,6 +48,10 @@ const Group = ({children, ...rest}) => { Button.Group = Group +Button.Group.propTypes = { + ...Box.propTypes +} + Button.propTypes = { as: PropTypes.oneOfType([PropTypes.oneOf(['button', 'a', 'summary', 'input']), PropTypes.func]), children: PropTypes.node, diff --git a/src/__tests__/Button.js b/src/__tests__/Button.js index f0b31990fde..5fb340df0eb 100644 --- a/src/__tests__/Button.js +++ b/src/__tests__/Button.js @@ -59,3 +59,27 @@ describe('ButtonOutline', () => { expect(render().type).toEqual('button') }) }) + + +describe('Button.Group', () => { + it('respects the "as" prop', () => { + expect(render().type).toEqual('a') + }) + + it('implements system props', () => { + expect(Button).toImplementSystemProps(COMMON) + expect(Button).toImplementSystemProps(layout) + }) + + it('adds the grouped class to children', () => { + const instance = render( + + - + ``` ## System props -`Button` and `Button.Group` components get `COMMON` system props. Read our [System Props](/components/docs/system-props) doc page for a full list of available props. +`Button` and `ButtonGroup` components get `COMMON` system props. Read our [System Props](/components/docs/system-props) doc page for a full list of available props. ## Component props @@ -33,12 +33,11 @@ To create a button group, wrap `Button` elements in the `Button.Group` element. | :- | :- | :-: | :- | | as | String | `button` | sets the HTML tag for the component | | disabled | Boolean | | sets the `disabled` attribute on the Button | -| grouped | Boolean | | allows you to use Button in a line of Buttons without duplicate borders | | onClick | Function | | function to be called when Button is clicked | | size | String | | use `sm` for a small Button, or `large` for a large Button -### Button.Group -`Button.Group` has access to the same props as `Box` +### ButtonGroup +`ButtonGroup` has access to the same props as `Box` export const meta = {displayName: 'Button'} diff --git a/src/Button.js b/src/Button.js index 6449649c576..dbc68ac2743 100644 --- a/src/Button.js +++ b/src/Button.js @@ -15,20 +15,9 @@ function fontSize({size = '14px', ...props}) { } } -const getClasses = props => { - const classes = [] - if (props.disabled) { - classes.push('disabled') - } - if (props.grouped) { - classes.push('grouped') - } - return classes.join(' ') -} - const Button = styled.button.attrs(props => ({ onClick: props.disabled ? undefined : props.onClick, - className: getClasses(props) + className: props.disabled ? 'disabled' : '' }))` ${props => (props.theme ? getButtonStyles(props.theme) : '')}; ${fontSize}; @@ -40,26 +29,10 @@ Button.defaultProps = { theme } -const Group = ({children, ...rest}) => { - const newChildren = React.Children.map(children, child => React.cloneElement(child, {grouped: true})) - return ( - - {newChildren} - - ) -} - -Button.Group = Group - -Button.Group.propTypes = { - ...Box.propTypes -} - Button.propTypes = { as: PropTypes.oneOfType([PropTypes.oneOf(['button', 'a', 'summary', 'input']), PropTypes.func]), children: PropTypes.node, disabled: PropTypes.bool, - grouped: PropTypes.bool, onClick: PropTypes.func, size: PropTypes.oneOf(['sm', 'large']), theme: PropTypes.object, diff --git a/src/ButtonGroup.js b/src/ButtonGroup.js new file mode 100644 index 00000000000..ce193344919 --- /dev/null +++ b/src/ButtonGroup.js @@ -0,0 +1,44 @@ +import styled from 'styled-components' +import Box from './Box' + +const ButtonGroup = styled(Box)` + display: inline-block; + vertical-align: middle; + + & > * { + position: relative; + border-right-width: 0; + border-radius: 0; + + :first-child { + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; + } + + :last-child { + border-right-width: 1px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + } + + :focus, + :active, + :hover { + border-right-width: 1px; + + * { + border-left-width: 0; + } + } + + :focus, + :active { + z-index: 1; + } + } +` + +ButtonGroup.propTypes = { + ...Box.propTypes, +} + +export default ButtonGroup diff --git a/src/__tests__/Button.js b/src/__tests__/Button.js index b9c34ccb284..6aa982a0362 100644 --- a/src/__tests__/Button.js +++ b/src/__tests__/Button.js @@ -1,6 +1,6 @@ import React from 'react' import {layout} from 'styled-system' -import {Button, ButtonPrimary, ButtonDanger, ButtonOutline} from '..' +import {Button, ButtonPrimary, ButtonDanger, ButtonOutline, ButtonGroup} from '..' import {render} from '../utils/testing' import {COMMON} from '../constants' @@ -60,24 +60,13 @@ describe('ButtonOutline', () => { }) }) -describe('Button.Group', () => { +describe('ButtonGroup', () => { it('respects the "as" prop', () => { - expect(render().type).toEqual('a') + expect(render().type).toEqual('a') }) it('implements system props', () => { - expect(Button).toImplementSystemProps(COMMON) - expect(Button).toImplementSystemProps(layout) - }) - - it('adds the grouped class to children', () => { - const instance = render( - -