From 1b22a98b5cf3ff7ef7148905a418fe2c03143ca8 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Mon, 7 Oct 2019 14:05:49 -0700 Subject: [PATCH 001/196] add web component dep --- package-lock.json | 5 +++++ package.json | 1 + src/SelectMenu.js | 0 3 files changed, 6 insertions(+) create mode 100644 src/SelectMenu.js diff --git a/package-lock.json b/package-lock.json index 0182adb3c08..eca557c2aa5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1084,6 +1084,11 @@ "integrity": "sha512-kBa+cDHOR9jpRJ+kcGMsysrls0leukrm68DmFQoMIWQcXdr2cZvyvypWuGYT7U+9kAExUE7+T7r6G3C3A6L8MQ==", "dev": true }, + "@github/details-menu-element": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@github/details-menu-element/-/details-menu-element-1.0.6.tgz", + "integrity": "sha512-fDZvy6UWIzkIyn4ls8UmzEpr1H8WhixaQQsLc4ZsyRKe+JFD45T96rWhWJjpJiAVwmTUbx7nX2gA5WpJS+mSxA==" + }, "@jest/console": { "version": "25.0.0", "resolved": "https://registry.npmjs.org/@jest/console/-/console-25.0.0.tgz", diff --git a/package.json b/package.json index 9bdda18ba61..8113eadf447 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "license": "MIT", "dependencies": { "@babel/polyfill": "7.4.4", + "@github/details-menu-element": "1.0.6", "@primer/octicons-react": "^9.1.1", "@reach/dialog": "0.2.9", "@styled-system/prop-types": "5.0.5", diff --git a/src/SelectMenu.js b/src/SelectMenu.js new file mode 100644 index 00000000000..e69de29bb2d From d25c1f0608c8ed10e501757a8781fa0b250a2c17 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Tue, 8 Oct 2019 10:02:59 -0700 Subject: [PATCH 002/196] add docs page --- docs/content/SelectMenu.md | 4 ++++ docs/src/@primer/gatsby-theme-doctocat/nav.yml | 2 ++ 2 files changed, 6 insertions(+) create mode 100644 docs/content/SelectMenu.md diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md new file mode 100644 index 00000000000..caafc25da3d --- /dev/null +++ b/docs/content/SelectMenu.md @@ -0,0 +1,4 @@ +--- +title: SelectMenu +--- + diff --git a/docs/src/@primer/gatsby-theme-doctocat/nav.yml b/docs/src/@primer/gatsby-theme-doctocat/nav.yml index d92326fa2cf..874b91e1d3b 100644 --- a/docs/src/@primer/gatsby-theme-doctocat/nav.yml +++ b/docs/src/@primer/gatsby-theme-doctocat/nav.yml @@ -52,6 +52,8 @@ url: /PointerBox - title: Position url: /Position + - title: SelectMenu + url: /SelectMenu - title: StateLabel url: /StateLabel - title: StyledOcticon From 541007a5a827d0cbf7e18d2db059318704c9db2c Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Tue, 8 Oct 2019 10:55:50 -0700 Subject: [PATCH 003/196] Add Modal & Summary --- docs/content/SelectMenu.md | 10 +++++ src/SelectMenu.js | 91 ++++++++++++++++++++++++++++++++++++++ src/index.js | 1 + 3 files changed, 102 insertions(+) diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index caafc25da3d..bba532ffce3 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -2,3 +2,13 @@ title: SelectMenu --- +```jsx live + + Robots + + + + + + +``` \ No newline at end of file diff --git a/src/SelectMenu.js b/src/SelectMenu.js index e69de29bb2d..f1e3a24f1ff 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -0,0 +1,91 @@ +import React from 'react' +import styled, {keyframes} from 'styled-components' +import {COMMON, get} from './constants' +import Button from './Button' +import theme from './theme' +import '@github/details-menu-element' + +const SelectMenu = styled.details` + &[open] > summary::before { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 80; + display: block; + cursor: default; + content: " "; + background: transparent; + } + // Remove marker added by the display: list-item browser default + > summary { list-style: none; } + // Remove marker added by details polyfill + > summary::before { display: none; } + // Remove marker added by Chrome + > summary::-webkit-details-marker { display: none; } + ${COMMON} +` + +const animateModal = keyframes` + 0% { + opacity: 0; + transform: scale(0.9); + } +` + +const ModalWrapper = styled.div` + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 99; + display: flex; + padding: ${get('space.3')}; + pointer-events: none; + flex-direction: column; + + &::before { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + pointer-events: none; + content: ""; + background-color: ${get('colors.blackfade50')}; + } + + .modal { + position: relative; + z-index: 99; // Needs to be higher than .details-overlay's z-index: 80. + display: flex; + max-height: 66%; + margin: auto 0; + overflow: hidden; // Enables border radius on scrollable child elements + pointer-events: auto; + flex-direction: column; + background-color: $gray-100; + border-radius: $border-radius * 2; + box-shadow: 0 0 18px rgba(0, 0, 0, 0.4); + animation: ${animateModal} 0.12s cubic-bezier(0, 0.1, 0.1, 1) backwards; + } +` + +SelectMenu.Summary = ({children, ...rest}) => + +SelectMenu.Modal = ({children, theme}) => { + return ( + + + {children} + + + ) +} + +SelectMenu.Modal.defaultProps = { + theme +} +export default SelectMenu \ No newline at end of file diff --git a/src/index.js b/src/index.js index 735d0de3f12..b3a9435cdce 100644 --- a/src/index.js +++ b/src/index.js @@ -31,6 +31,7 @@ export {default as Heading} from './Heading' export {default as Label} from './Label' export {default as Link} from './Link' export {default as PointerBox} from './PointerBox' +export {default as SelectMenu} from './SelectMenu' export {default as StateLabel} from './StateLabel' export {default as StyledOcticon} from './StyledOcticon' export {default as TabNav} from './TabNav' From 4a9e197f1ca7b6399562242929dad002ee9d0b72 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Tue, 8 Oct 2019 11:27:35 -0700 Subject: [PATCH 004/196] add Header, Title, and breakpoints --- docs/content/SelectMenu.md | 3 ++ src/SelectMenu.js | 63 ++++++++++++++++++++++++++++++++++++-- src/theme.js | 3 ++ 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index bba532ffce3..27759dec478 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -6,6 +6,9 @@ title: SelectMenu Robots + + hi!!! + diff --git a/src/SelectMenu.js b/src/SelectMenu.js index f1e3a24f1ff..4803e0516d8 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -2,6 +2,8 @@ import React from 'react' import styled, {keyframes} from 'styled-components' import {COMMON, get} from './constants' import Button from './Button' +import Flex from './Flex' +import Heading from './Heading' import theme from './theme' import '@github/details-menu-element' @@ -42,7 +44,7 @@ const ModalWrapper = styled.div` left: 0; z-index: 99; display: flex; - padding: ${get('space.3')}; + padding: ${get('space.3')}px; pointer-events: none; flex-direction: column; @@ -55,6 +57,10 @@ const ModalWrapper = styled.div` pointer-events: none; content: ""; background-color: ${get('colors.blackfade50')}; + + @media (min-width: ${get('breakpoints.0')}) { + display: none; + } } .modal { @@ -66,10 +72,30 @@ const ModalWrapper = styled.div` overflow: hidden; // Enables border radius on scrollable child elements pointer-events: auto; flex-direction: column; - background-color: $gray-100; - border-radius: $border-radius * 2; + background-color: ${get('colors.gray.1')}; + border-radius: ${get('radii.1') *2}px; box-shadow: 0 0 18px rgba(0, 0, 0, 0.4); animation: ${animateModal} 0.12s cubic-bezier(0, 0.1, 0.1, 1) backwards; + + @media (min-width: ${get('breakpoints.0')}) { + width: 300px; + height: auto; + max-height: 350px; + margin: ${get('space.1')}px 0 ${get('space.3')}px 0; + font-size: ${get('fontSizes.0')}px; + border: ${get('borders.1')} ${get('colors.borders.grayDark')}; + border-radius: ${get('radii.1')}px; + box-shadow: $box-shadow-medium; + } + } + + @media (min-width: ${get('breakpoints.0')}) { + position: absolute; + top: auto; + right: auto; + bottom: auto; + left: auto; + padding: 0; } ` @@ -88,4 +114,35 @@ SelectMenu.Modal = ({children, theme}) => { SelectMenu.Modal.defaultProps = { theme } + +SelectMenu.Header = styled.header` + display: flex; + flex: none; // fixes header from getting squeezed in Safari iOS + padding: ${get('space.3')}; + + @media (min-width: ${get('breakpoints.0')}) { + padding-top: ${get('space.2')}px; + padding-bottom: ${get('space.2')}px; + } +` + +SelectMenu.Header.defaultProps = { + theme +} + +SelectMenu.Title = styled.h3` + flex: auto; + font-size: ${get('fontSizes.1')}px; + font-weight: ${get('fontWeights.bold')}; + margin: 0; + + @media (min-width: ${get('breakpoints.0')}) { + font-size: inherit; + } +` + +SelectMenu.Title.defaultProps = { + theme +} + export default SelectMenu \ No newline at end of file diff --git a/src/theme.js b/src/theme.js index 6ef1df9c2dd..bd87eeb4530 100644 --- a/src/theme.js +++ b/src/theme.js @@ -25,6 +25,9 @@ const colors = { success: green[5], unknown: gray[4] }, + borders: { + grayDark: '#d1d5da' + }, button: { disabledColor: 'rgba(36, 41, 46, 0.4)', bg2: 'rgb(239, 243, 246)', From 7b38b657b294951d725e9821d82c727f72b66f5d Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Tue, 8 Oct 2019 13:06:13 -0700 Subject: [PATCH 005/196] start adding filter --- docs/content/SelectMenu.md | 3 ++- src/SelectMenu.js | 43 +++++++++++++++++++++++++++++++------- src/TextInput.js | 6 +++--- src/theme.js | 1 + 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index 27759dec478..da4662a0c2d 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -7,8 +7,9 @@ title: SelectMenu Robots - hi!!! + Filter by Author + diff --git a/src/SelectMenu.js b/src/SelectMenu.js index 4803e0516d8..acbab13be99 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -1,9 +1,7 @@ import React from 'react' import styled, {keyframes} from 'styled-components' -import {COMMON, get} from './constants' +import {COMMON, TYPOGRAPHY, get} from './constants' import Button from './Button' -import Flex from './Flex' -import Heading from './Heading' import theme from './theme' import '@github/details-menu-element' @@ -67,8 +65,10 @@ const ModalWrapper = styled.div` position: relative; z-index: 99; // Needs to be higher than .details-overlay's z-index: 80. display: flex; - max-height: 66%; + ${props => props.filter ? 'height: 80%' : ''}; + max-height: ${props => props.filter ? 'none' : '66%'}; margin: auto 0; + ${props => props.filter ? 'margin-top: 0' : ''}; overflow: hidden; // Enables border radius on scrollable child elements pointer-events: auto; flex-direction: column; @@ -78,7 +78,7 @@ const ModalWrapper = styled.div` animation: ${animateModal} 0.12s cubic-bezier(0, 0.1, 0.1, 1) backwards; @media (min-width: ${get('breakpoints.0')}) { - width: 300px; + width: ${props => props.filter ? 'auto' : '300px'}; height: auto; max-height: 350px; margin: ${get('space.1')}px 0 ${get('space.3')}px 0; @@ -101,7 +101,7 @@ const ModalWrapper = styled.div` SelectMenu.Summary = ({children, ...rest}) => -SelectMenu.Modal = ({children, theme}) => { +SelectMenu.Modal = ({children, filter, theme}) => { return ( @@ -118,7 +118,7 @@ SelectMenu.Modal.defaultProps = { SelectMenu.Header = styled.header` display: flex; flex: none; // fixes header from getting squeezed in Safari iOS - padding: ${get('space.3')}; + padding: ${get('space.3')}px; @media (min-width: ${get('breakpoints.0')}) { padding-top: ${get('space.2')}px; @@ -135,6 +135,8 @@ SelectMenu.Title = styled.h3` font-size: ${get('fontSizes.1')}px; font-weight: ${get('fontWeights.bold')}; margin: 0; + ${COMMON} + ${TYPOGRAPHY} @media (min-width: ${get('breakpoints.0')}) { font-size: inherit; @@ -145,4 +147,31 @@ SelectMenu.Title.defaultProps = { theme } +const StyledForm = styled.form` + padding: ${get('space.3')}px; + margin: 0; + border-top: ${get('borders.1')} ${get('colors.borders.gray')}; + + @media (min-width: ${get('breakpoints.0')}) { + padding: ${get('space.2')}px; + } +` + +const StyledInput = styled.input` + display: block; + width: 100%; + + @media (min-width: ${get('breakpoints.0')}) { + font-size: ${get('fontSizes.1')}px; + } +` + + +SelectMenu.Filter = (props) => { + return ( + + + + ) +} export default SelectMenu \ No newline at end of file diff --git a/src/TextInput.js b/src/TextInput.js index d2da8dada80..7b777d8de93 100644 --- a/src/TextInput.js +++ b/src/TextInput.js @@ -45,13 +45,13 @@ const TextInput = styled(TextInputBase)` min-height: 28px; padding-top: 3px; padding-bottom: 3px; - font-size: $font-size-small; + font-size: ${get('fontSizes.0')}px; line-height: 20px; } &.input-lg { - padding: $spacer-1 10px; - font-size: $h4-size; + padding: ${get('space.1')}px 10px; + font-size: ${get('fontSizes.3')}; } &.input-block { diff --git a/src/theme.js b/src/theme.js index bd87eeb4530..0e91818a192 100644 --- a/src/theme.js +++ b/src/theme.js @@ -26,6 +26,7 @@ const colors = { unknown: gray[4] }, borders: { + gray: gray[2], grayDark: '#d1d5da' }, button: { From a1be8ff5f3b523dccc47d61f766b76c329876ab4 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Tue, 8 Oct 2019 15:46:44 -0700 Subject: [PATCH 006/196] don't need to import CE package in file --- src/SelectMenu.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SelectMenu.js b/src/SelectMenu.js index acbab13be99..2558298dd99 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -3,7 +3,6 @@ import styled, {keyframes} from 'styled-components' import {COMMON, TYPOGRAPHY, get} from './constants' import Button from './Button' import theme from './theme' -import '@github/details-menu-element' const SelectMenu = styled.details` &[open] > summary::before { From edc436cbda9103b480415e57a1b17f78f5bf1430 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Thu, 10 Oct 2019 10:21:57 -0700 Subject: [PATCH 007/196] add @binarymuse TextInput updates Co-Authors @binarymuse --- docs/content/TextInput.md | 15 ++----- index.d.ts | 3 +- src/TextInput.js | 82 ++++++++++++++++----------------------- 3 files changed, 39 insertions(+), 61 deletions(-) diff --git a/docs/content/TextInput.md b/docs/content/TextInput.md index 6ebf0a743a6..f02f0b32991 100644 --- a/docs/content/TextInput.md +++ b/docs/content/TextInput.md @@ -6,7 +6,7 @@ TextInput is a form component to add default styling to the native text input. D ## Default example ```jsx live - + ``` ## System props @@ -15,16 +15,9 @@ TextInput components get `COMMON` system props. Read our [System Props](/system- ## Component props +Native `input` attributes are forwarded to the underlying React `input` component and are not listed below. + | Name | Type | Default | Description | | :- | :- | :-: | :- | -| autocomplete | String | | Allows user to set `autocomplete` attribute on input. See [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-autocomplete) for attribute documentation. | -| aria-label | String | | Label that describes the input for screen reader users | | block | Boolean | | Adds `display: block` to element | -| disabled | Boolean | | Sets the `disabled` attribute on the element | -| id | String | | Sets the `id` attribute on the element | -| name | String | | Sets the `name` attribute on the element | -| onChange | Function | | Function to be called when content in Input changes | -| placeholder | String | | Sets the placeholder text | -| required | Boolean | | Sets the `required` attribute on the element | -| size | String | | Can be either `small` or `large`. Creates a smaller or larger input than the default. -| value | String | | Current value of the Input. | +| variant | String | | Can be either `small` or `large`. Creates a smaller or larger input than the default. \ No newline at end of file diff --git a/index.d.ts b/index.d.ts index 3edffeb6370..620b64c7aad 100644 --- a/index.d.ts +++ b/index.d.ts @@ -267,9 +267,8 @@ declare module '@primer/components' { export interface TextInputProps extends CommonProps, Omit, 'color' | 'size'> { - autocomplete?: string block?: boolean - size?: 'small' | 'large' + variant?: 'small' | 'large' } export const TextInput: React.FunctionComponent diff --git a/src/TextInput.js b/src/TextInput.js index 7b777d8de93..509683501ca 100644 --- a/src/TextInput.js +++ b/src/TextInput.js @@ -1,26 +1,31 @@ -import React from 'react' -import classnames from 'classnames' import PropTypes from 'prop-types' -import styled from 'styled-components' +import systemPropTypes from '@styled-system/prop-types' +import styled, {css} from 'styled-components' +import {variant, width} from 'styled-system' import {COMMON, get} from './constants' import theme from './theme' -function TextInputBase({autocomplete, theme, size, block, className, ...rest}) { - const classes = classnames(className, 'form-control', { - 'input-block': block, - 'input-sm': size === 'small', - 'input-lg': size === 'large' - }) - const inputProps = { - className: classes, - autoComplete: autocomplete, - type: 'text', - ...rest +const sizeVariants = variant({ + variants: { + small: { + minHeight: '28px', + px: 2, + py: '3px', + fontSize: 0, + lineHeight: '20px' + }, + large: { + px: 2, + py: '10px', + fontSize: 3 + } } - return -} +}) -const TextInput = styled(TextInputBase)` +const TextInput = styled.input.attrs(({theme, variant, block, ...rest}) => ({ + type: 'text', + ...rest +}))` min-height: 34px; padding: 6px ${get('space.2')}px; font-size: ${get('fontSizes.2')}px; @@ -34,53 +39,34 @@ const TextInput = styled(TextInputBase)` border-radius: ${get('radii.1')}px; outline: none; box-shadow: ${get('shadows.formControl')}; - &:focus { border-color: ${get('colors.blue.4')}; outline: none; box-shadow: ${get('shadows.formControl')}, ${get('shadows.formControlFocus')}; } - - &.input-sm { - min-height: 28px; - padding-top: 3px; - padding-bottom: 3px; - font-size: ${get('fontSizes.0')}px; - line-height: 20px; - } - - &.input-lg { - padding: ${get('space.1')}px 10px; - font-size: ${get('fontSizes.3')}; - } - - &.input-block { - display: block; - width: 100%; - } - + ${sizeVariants} + ${props => + props.block && + css` + display: block; + width: 100%; + `} // Ensures inputs don't zoom on mobile but are body-font size on desktop @media (max-width: ${get('breakpoints.1')}) { font-size: ${get('fontSizes.1')}px; } ${COMMON}; + ${width} ` TextInput.defaultProps = {theme} TextInput.propTypes = { - autocomplete: PropTypes.string, block: PropTypes.bool, - disabled: PropTypes.bool, - id: PropTypes.string, - name: PropTypes.string, - onChange: PropTypes.func, - placeholder: PropTypes.string, - required: PropTypes.bool, - size: PropTypes.oneOf(['small', 'large']), theme: PropTypes.object, - value: PropTypes.string, - ...COMMON.propTypes + variant: PropTypes.oneOf(['small', 'large']), + ...COMMON.propTypes, + width: systemPropTypes.layout.width } -export default TextInput +export default TextInput \ No newline at end of file From 4e9ae38bdd21cacad01a1fc5c9862cddd62434e8 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Fri, 11 Oct 2019 09:57:04 -0700 Subject: [PATCH 008/196] fixes --- docs/content/SelectMenu.md | 8 ++- src/SelectMenu.js | 131 +++++++++++++++++++++++++++++++++---- src/TextInput.js | 2 +- 3 files changed, 124 insertions(+), 17 deletions(-) diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index da4662a0c2d..1b1c9a29eba 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -10,9 +10,11 @@ title: SelectMenu Filter by Author - - - + + + + + ``` \ No newline at end of file diff --git a/src/SelectMenu.js b/src/SelectMenu.js index 2558298dd99..c78a92c5f59 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -2,6 +2,7 @@ import React from 'react' import styled, {keyframes} from 'styled-components' import {COMMON, TYPOGRAPHY, get} from './constants' import Button from './Button' +import TextInput from './TextInput' import theme from './theme' const SelectMenu = styled.details` @@ -72,7 +73,7 @@ const ModalWrapper = styled.div` pointer-events: auto; flex-direction: column; background-color: ${get('colors.gray.1')}; - border-radius: ${get('radii.1') *2}px; + border-radius: 6px; box-shadow: 0 0 18px rgba(0, 0, 0, 0.4); animation: ${animateModal} 0.12s cubic-bezier(0, 0.1, 0.1, 1) backwards; @@ -84,7 +85,7 @@ const ModalWrapper = styled.div` font-size: ${get('fontSizes.0')}px; border: ${get('borders.1')} ${get('colors.borders.grayDark')}; border-radius: ${get('radii.1')}px; - box-shadow: $box-shadow-medium; + box-shadow: 0 1px 5px ${get('colors.borders.blackfade15')} !default; } } @@ -156,21 +157,125 @@ const StyledForm = styled.form` } ` -const StyledInput = styled.input` - display: block; - width: 100%; - - @media (min-width: ${get('breakpoints.0')}) { - font-size: ${get('fontSizes.1')}px; - } -` - - SelectMenu.Filter = (props) => { return ( - + ) } + +const transformChildren = children => { + return React.Children.map(children, child => { + return React.cloneElement(child, {role: 'menuitem', className: `${child.props.className ? child.props.className + ' ' : ''}SelectMenu--list-item`}) + }) +} + +SelectMenu.List = styled.div.attrs(props => ({ + children: transformChildren(props.children) +}))` + position: relative; + padding: 0; + margin: 0; + flex: auto; + overflow-x: hidden; + overflow-y: auto; + background-color: ${get('colors.white')}; + border-top: ${get('borders.1')} ${get('colors.borders.gray')}; + -webkit-overflow-scrolling: touch; // Adds momentum + bouncy scrolling + + .SelectMenu--list-item { + display: flex; + align-items: center; + width: 100%; + padding: ${get('space.3')}px; + overflow: hidden; + color: ${get('colors.gray.6')}; + text-align: left; + cursor: pointer; + background-color: ${get('colors.white')}; + border: 0; + + & + & { + // Add a top border only if the above element also is a list item + border-top: ${get('borders.1')} ${get('colors.gray.2')}; + } + + &:hover { + text-decoration: none; + } + + &:focus { + outline:none; + } + + @media (min-width: ${get('breakpoints.0')}) { + padding-top: ${get('space.2')}px; + padding-bottom: ${get('space.2')}px; + } + } + + .SelectMenu--list-item[aria-checked="true"] { + font-weight: 500; + color: ${get('colors.gray.9')}; + + .SelectMenu-icon { + visibility: visible; + transition: transform 0.12s cubic-bezier(0, 0, 0.2, 1), visibility 0s linear; + transform: scale(1); + } + } + + @media (hover: hover) { + body:not(.intent-mouse) .SelectMenu--list-item:focus, + .SelectMenu--list-item:hover { + color: ${get('colors.white')}; + background-color: ${get('colors.blue.5')}; + } + + .SelectMenu--list-item:active { + color: ${get('colors.white')}; + background-color: ${get('colors.blue.4')}; + } + + body:not(.intent-mouse) .SelectMenu-tab:focus { + background-color: ${get('colors.blue.1')}; + } + + .SelectMenu-tab:not([aria-checked="true"]):hover { + color: ${get('colors.gray.9')}; + background-color: ${get('colors.gray.2')}; + } + + .SelectMenu-tab:not([aria-checked="true"]):active { + color: ${get('colors.gray.9')}; + background-color: ${get('colors.gray.1')}; + } + } + + // Can not hover states + // + // For touch input + + @media (hover: none) { + // Android + .SelectMenu--list-item:focus, + .SelectMenu--list-item:active { + background-color: ${get('colors.gray.0')}; + } + + // iOS Safari + // :active would work if ontouchstart is added to the button + // Instead this tweaks the "native" highlight color + .SelectMenu--list-item { + -webkit-tap-highlight-color: rgba(${get('colors.gray.3')}, 0.5); + } + } + +` + +SelectMenu.List.defaultProps = { + theme +} + export default SelectMenu \ No newline at end of file diff --git a/src/TextInput.js b/src/TextInput.js index 509683501ca..a0c1a9a5151 100644 --- a/src/TextInput.js +++ b/src/TextInput.js @@ -52,7 +52,7 @@ const TextInput = styled.input.attrs(({theme, variant, block, ...rest}) => ({ width: 100%; `} // Ensures inputs don't zoom on mobile but are body-font size on desktop - @media (max-width: ${get('breakpoints.1')}) { + @media (min-width: ${get('breakpoints.0')}) { font-size: ${get('fontSizes.1')}px; } ${COMMON}; From de73a7e78c5cf09d086544187b32e33484216f8e Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Fri, 11 Oct 2019 16:07:45 -0700 Subject: [PATCH 009/196] refactor styles --- src/SelectMenu.js | 203 +++------------------------------------- src/SelectMenuStyles.js | 194 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+), 190 deletions(-) create mode 100644 src/SelectMenuStyles.js diff --git a/src/SelectMenu.js b/src/SelectMenu.js index c78a92c5f59..6fce7c08d91 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -1,102 +1,19 @@ import React from 'react' -import styled, {keyframes} from 'styled-components' +import styled from 'styled-components' import {COMMON, TYPOGRAPHY, get} from './constants' import Button from './Button' import TextInput from './TextInput' import theme from './theme' +import classnames from 'classnames' +import {modalStyles, wrapperStyles, listStyles} from './SelectMenuStyles' const SelectMenu = styled.details` - &[open] > summary::before { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 80; - display: block; - cursor: default; - content: " "; - background: transparent; - } - // Remove marker added by the display: list-item browser default - > summary { list-style: none; } - // Remove marker added by details polyfill - > summary::before { display: none; } - // Remove marker added by Chrome - > summary::-webkit-details-marker { display: none; } + ${wrapperStyles} ${COMMON} ` -const animateModal = keyframes` - 0% { - opacity: 0; - transform: scale(0.9); - } -` - const ModalWrapper = styled.div` - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 99; - display: flex; - padding: ${get('space.3')}px; - pointer-events: none; - flex-direction: column; - - &::before { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - pointer-events: none; - content: ""; - background-color: ${get('colors.blackfade50')}; - - @media (min-width: ${get('breakpoints.0')}) { - display: none; - } - } - - .modal { - position: relative; - z-index: 99; // Needs to be higher than .details-overlay's z-index: 80. - display: flex; - ${props => props.filter ? 'height: 80%' : ''}; - max-height: ${props => props.filter ? 'none' : '66%'}; - margin: auto 0; - ${props => props.filter ? 'margin-top: 0' : ''}; - overflow: hidden; // Enables border radius on scrollable child elements - pointer-events: auto; - flex-direction: column; - background-color: ${get('colors.gray.1')}; - border-radius: 6px; - box-shadow: 0 0 18px rgba(0, 0, 0, 0.4); - animation: ${animateModal} 0.12s cubic-bezier(0, 0.1, 0.1, 1) backwards; - - @media (min-width: ${get('breakpoints.0')}) { - width: ${props => props.filter ? 'auto' : '300px'}; - height: auto; - max-height: 350px; - margin: ${get('space.1')}px 0 ${get('space.3')}px 0; - font-size: ${get('fontSizes.0')}px; - border: ${get('borders.1')} ${get('colors.borders.grayDark')}; - border-radius: ${get('radii.1')}px; - box-shadow: 0 1px 5px ${get('colors.borders.blackfade15')} !default; - } - } - - @media (min-width: ${get('breakpoints.0')}) { - position: absolute; - top: auto; - right: auto; - bottom: auto; - left: auto; - padding: 0; - } + ${modalStyles} ` SelectMenu.Summary = ({children, ...rest}) => @@ -167,112 +84,18 @@ SelectMenu.Filter = (props) => { const transformChildren = children => { return React.Children.map(children, child => { - return React.cloneElement(child, {role: 'menuitem', className: `${child.props.className ? child.props.className + ' ' : ''}SelectMenu--list-item`}) + return React.cloneElement(child, {role: 'menuitem', className: classnames(child.props.className, 'SelectMenu--list-item')}) }) } -SelectMenu.List = styled.div.attrs(props => ({ - children: transformChildren(props.children) -}))` - position: relative; - padding: 0; - margin: 0; - flex: auto; - overflow-x: hidden; - overflow-y: auto; - background-color: ${get('colors.white')}; - border-top: ${get('borders.1')} ${get('colors.borders.gray')}; - -webkit-overflow-scrolling: touch; // Adds momentum + bouncy scrolling - - .SelectMenu--list-item { - display: flex; - align-items: center; - width: 100%; - padding: ${get('space.3')}px; - overflow: hidden; - color: ${get('colors.gray.6')}; - text-align: left; - cursor: pointer; - background-color: ${get('colors.white')}; - border: 0; - - & + & { - // Add a top border only if the above element also is a list item - border-top: ${get('borders.1')} ${get('colors.gray.2')}; - } - - &:hover { - text-decoration: none; - } - - &:focus { - outline:none; - } - - @media (min-width: ${get('breakpoints.0')}) { - padding-top: ${get('space.2')}px; - padding-bottom: ${get('space.2')}px; - } - } - - .SelectMenu--list-item[aria-checked="true"] { - font-weight: 500; - color: ${get('colors.gray.9')}; - - .SelectMenu-icon { - visibility: visible; - transition: transform 0.12s cubic-bezier(0, 0, 0.2, 1), visibility 0s linear; - transform: scale(1); - } - } - - @media (hover: hover) { - body:not(.intent-mouse) .SelectMenu--list-item:focus, - .SelectMenu--list-item:hover { - color: ${get('colors.white')}; - background-color: ${get('colors.blue.5')}; - } - - .SelectMenu--list-item:active { - color: ${get('colors.white')}; - background-color: ${get('colors.blue.4')}; - } - - body:not(.intent-mouse) .SelectMenu-tab:focus { - background-color: ${get('colors.blue.1')}; - } - - .SelectMenu-tab:not([aria-checked="true"]):hover { - color: ${get('colors.gray.9')}; - background-color: ${get('colors.gray.2')}; - } - - .SelectMenu-tab:not([aria-checked="true"]):active { - color: ${get('colors.gray.9')}; - background-color: ${get('colors.gray.1')}; - } - } - - // Can not hover states - // - // For touch input - - @media (hover: none) { - // Android - .SelectMenu--list-item:focus, - .SelectMenu--list-item:active { - background-color: ${get('colors.gray.0')}; - } - - // iOS Safari - // :active would work if ontouchstart is added to the button - // Instead this tweaks the "native" highlight color - .SelectMenu--list-item { - -webkit-tap-highlight-color: rgba(${get('colors.gray.3')}, 0.5); - } - } - +const StyledList = styled.div` + ${listStyles} ` +SelectMenu.List = ({children, ...rest}) => { + return ( + {transformChildren(children)} + ) +} SelectMenu.List.defaultProps = { theme diff --git a/src/SelectMenuStyles.js b/src/SelectMenuStyles.js new file mode 100644 index 00000000000..411f8532fa8 --- /dev/null +++ b/src/SelectMenuStyles.js @@ -0,0 +1,194 @@ +import {get} from './constants' +import {keyframes, css} from 'styled-components' + +const animateModal = keyframes` + 0% { + opacity: 0; + transform: scale(0.9); + } +` +export const modalStyles = css` + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 99; + display: flex; + padding: ${get('space.3')}px; + pointer-events: none; + flex-direction: column; + + &::before { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + pointer-events: none; + content: ""; + background-color: ${get('colors.blackfade50')}; + + @media (min-width: ${get('breakpoints.0')}) { + display: none; + } + } + + .modal { + position: relative; + z-index: 99; // Needs to be higher than .details-overlay's z-index: 80. + display: flex; + ${props => props.filter ? 'height: 80%' : ''}; + max-height: ${props => props.filter ? 'none' : '66%'}; + margin: auto 0; + ${props => props.filter ? 'margin-top: 0' : ''}; + overflow: hidden; // Enables border radius on scrollable child elements + pointer-events: auto; + flex-direction: column; + background-color: ${get('colors.gray.1')}; + border-radius: 6px; + box-shadow: 0 0 18px rgba(0, 0, 0, 0.4); + animation: ${animateModal} 0.12s cubic-bezier(0, 0.1, 0.1, 1) backwards; + + @media (min-width: ${get('breakpoints.0')}) { + width: ${props => props.filter ? 'auto' : '300px'}; + height: auto; + max-height: 350px; + margin: ${get('space.1')}px 0 ${get('space.3')}px 0; + font-size: ${get('fontSizes.0')}px; + border: ${get('borders.1')} ${get('colors.borders.grayDark')}; + border-radius: ${get('radii.1')}px; + box-shadow: 0 1px 5px ${get('colors.borders.blackfade15')} !default; + } + } + + @media (min-width: ${get('breakpoints.0')}) { + position: absolute; + top: auto; + right: auto; + bottom: auto; + left: auto; + padding: 0; + } +` + +export const wrapperStyles = css` + &[open] > summary::before { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 80; + display: block; + cursor: default; + content: " "; + background: transparent; + } + // Remove marker added by the display: list-item browser default + > summary { list-style: none; } + // Remove marker added by details polyfill + > summary::before { display: none; } + // Remove marker added by Chrome + > summary::-webkit-details-marker { display: none; } +` + +export const listStyles = css` + position: relative; + padding: 0; + margin: 0; + flex: auto; + overflow-x: hidden; + overflow-y: auto; + background-color: ${get('colors.white')}; + border-top: ${get('borders.1')} ${get('colors.borders.gray')}; + -webkit-overflow-scrolling: touch; // Adds momentum + bouncy scrolling + + .SelectMenu--list-item { + display: flex; + align-items: center; + width: 100%; + padding: ${get('space.3')}px; + overflow: hidden; + color: ${get('colors.gray.6')}; + text-align: left; + cursor: pointer; + background-color: ${get('colors.white')}; + border: 0; + + & + & { + // Add a top border only if the above element also is a list item + border-top: ${get('borders.1')} ${get('colors.gray.2')}; + } + + &:hover { + text-decoration: none; + } + + &:focus { + outline:none; + } + + @media (min-width: ${get('breakpoints.0')}) { + padding-top: ${get('space.2')}px; + padding-bottom: ${get('space.2')}px; + } + } + + .SelectMenu--list-item[aria-checked="true"] { + font-weight: 500; + color: ${get('colors.gray.9')}; + + .SelectMenu-icon { + visibility: visible; + transition: transform 0.12s cubic-bezier(0, 0, 0.2, 1), visibility 0s linear; + transform: scale(1); + } + } + + @media (hover: hover) { + body:not(.intent-mouse) .SelectMenu--list-item:focus, + .SelectMenu--list-item:hover { + color: ${get('colors.white')}; + background-color: ${get('colors.blue.5')}; + } + + .SelectMenu--list-item:active { + color: ${get('colors.white')}; + background-color: ${get('colors.blue.4')}; + } + + body:not(.intent-mouse) .SelectMenu-tab:focus { + background-color: ${get('colors.blue.1')}; + } + + .SelectMenu-tab:not([aria-checked="true"]):hover { + color: ${get('colors.gray.9')}; + background-color: ${get('colors.gray.2')}; + } + + .SelectMenu-tab:not([aria-checked="true"]):active { + color: ${get('colors.gray.9')}; + background-color: ${get('colors.gray.1')}; + } + } + + // Can not hover states + // + // For touch input + + @media (hover: none) { + // Android + .SelectMenu--list-item:focus, + .SelectMenu--list-item:active { + background-color: ${get('colors.gray.0')}; + } + + // iOS Safari + // :active would work if ontouchstart is added to the button + // Instead this tweaks the "native" highlight color + .SelectMenu--list-item { + -webkit-tap-highlight-color: rgba(${get('colors.gray.3')}, 0.5); + } + } +` \ No newline at end of file From 144a232a6d477e01adaa48b77fb0b7e8305fc242 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Mon, 14 Oct 2019 15:42:28 -0700 Subject: [PATCH 010/196] tab styles --- docs/content/SelectMenu.md | 4 +++ src/SelectMenu.js | 60 ++++++++++++++++++++++++++++++++++++++ src/SelectMenuStyles.js | 6 ++-- 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index 1b1c9a29eba..04fee4cf472 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -10,6 +10,10 @@ title: SelectMenu Filter by Author + + Users + Repos + diff --git a/src/SelectMenu.js b/src/SelectMenu.js index 6fce7c08d91..5e11de246b7 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -101,4 +101,64 @@ SelectMenu.List.defaultProps = { theme } +SelectMenu.Tabs = styled.nav` + display: flex; + flex-shrink: 0; + margin-bottom: -1px; // hide border of element below + overflow-x: auto; + overflow-y: hidden; + border-top: ${get('borders.1')} ${get('colors.borders.gray')}; + -webkit-overflow-scrolling: touch; + + // Hide scrollbar so it doesn't cover the text + &::-webkit-scrollbar { + display: none; + } + + @media (min-width: ${get('breakpoints.0')}) { + padding: 0 ${get('space.2')}px; + border-top: 0; + } +` + +SelectMenu.Tab = styled.button.attrs(props => ({ + className: 'SelectMenuTab', + "aria-selected": props.selected +}))` + flex: 1; + padding: ${get('space.2')}px ${get('space.3')}px; + font-size: ${get('fontSizes.0')}px; + font-weight: 500; + color: ${get('colors.gray.5')}; + text-align: center; + background-color: transparent; + border: 0; + box-shadow: inset 0 -1px 0 ${get('colors.borders.gray')}; + + &:focus { + outline: none; + } + + @media (min-width: ${get('breakpoints.0')}) { + flex: none; + padding: ${get('space.1')}px ${get('space.3')}px; + border: ${get('borders.1')} transparent; + border-bottom-width: 0; + border-top-left-radius: ${get('radii.1')}px; + border-top-right-radius: ${get('radii.1')}px; + } + + &[aria-selected="true"] { + z-index: 1; // Keeps box-shadow visible when hovering + color: ${get('colors.gray.9')}; + background-color: ${get('colors.white')}; + box-shadow: 0 0 0 1px ${get('colors.borders.gray')}; + + @media (min-width: ${get('breakpoints.0')}) { + border-color: ${get('colors.borders.gray')}; + box-shadow: none; + } + } +` + export default SelectMenu \ No newline at end of file diff --git a/src/SelectMenuStyles.js b/src/SelectMenuStyles.js index 411f8532fa8..0ec547a63e1 100644 --- a/src/SelectMenuStyles.js +++ b/src/SelectMenuStyles.js @@ -158,16 +158,16 @@ export const listStyles = css` background-color: ${get('colors.blue.4')}; } - body:not(.intent-mouse) .SelectMenu-tab:focus { + body:not(.intent-mouse) .SelectMenuTab:focus { background-color: ${get('colors.blue.1')}; } - .SelectMenu-tab:not([aria-checked="true"]):hover { + .SelectMenuTab:not([aria-checked="true"]):hover { color: ${get('colors.gray.9')}; background-color: ${get('colors.gray.2')}; } - .SelectMenu-tab:not([aria-checked="true"]):active { + .SelectMenuTab:not([aria-checked="true"]):active { color: ${get('colors.gray.9')}; background-color: ${get('colors.gray.1')}; } From 83e15239bd272543b2dc40389faacc7dd5059c92 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Mon, 14 Oct 2019 15:52:37 -0700 Subject: [PATCH 011/196] move CSS --- src/SelectMenu.js | 55 +++------------------------------------ src/SelectMenuStyles.js | 57 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 52 deletions(-) diff --git a/src/SelectMenu.js b/src/SelectMenu.js index 5e11de246b7..f201af2a4f1 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -5,7 +5,7 @@ import Button from './Button' import TextInput from './TextInput' import theme from './theme' import classnames from 'classnames' -import {modalStyles, wrapperStyles, listStyles} from './SelectMenuStyles' +import {modalStyles, wrapperStyles, listStyles, tabStyles, tabWrapperStyles} from './SelectMenuStyles' const SelectMenu = styled.details` ${wrapperStyles} @@ -102,63 +102,14 @@ SelectMenu.List.defaultProps = { } SelectMenu.Tabs = styled.nav` - display: flex; - flex-shrink: 0; - margin-bottom: -1px; // hide border of element below - overflow-x: auto; - overflow-y: hidden; - border-top: ${get('borders.1')} ${get('colors.borders.gray')}; - -webkit-overflow-scrolling: touch; - - // Hide scrollbar so it doesn't cover the text - &::-webkit-scrollbar { - display: none; - } - - @media (min-width: ${get('breakpoints.0')}) { - padding: 0 ${get('space.2')}px; - border-top: 0; - } + ${tabWrapperStyles} ` SelectMenu.Tab = styled.button.attrs(props => ({ className: 'SelectMenuTab', "aria-selected": props.selected }))` - flex: 1; - padding: ${get('space.2')}px ${get('space.3')}px; - font-size: ${get('fontSizes.0')}px; - font-weight: 500; - color: ${get('colors.gray.5')}; - text-align: center; - background-color: transparent; - border: 0; - box-shadow: inset 0 -1px 0 ${get('colors.borders.gray')}; - - &:focus { - outline: none; - } - - @media (min-width: ${get('breakpoints.0')}) { - flex: none; - padding: ${get('space.1')}px ${get('space.3')}px; - border: ${get('borders.1')} transparent; - border-bottom-width: 0; - border-top-left-radius: ${get('radii.1')}px; - border-top-right-radius: ${get('radii.1')}px; - } - - &[aria-selected="true"] { - z-index: 1; // Keeps box-shadow visible when hovering - color: ${get('colors.gray.9')}; - background-color: ${get('colors.white')}; - box-shadow: 0 0 0 1px ${get('colors.borders.gray')}; - - @media (min-width: ${get('breakpoints.0')}) { - border-color: ${get('colors.borders.gray')}; - box-shadow: none; - } - } + ${tabStyles} ` export default SelectMenu \ No newline at end of file diff --git a/src/SelectMenuStyles.js b/src/SelectMenuStyles.js index 0ec547a63e1..57cbbb6a176 100644 --- a/src/SelectMenuStyles.js +++ b/src/SelectMenuStyles.js @@ -191,4 +191,61 @@ export const listStyles = css` -webkit-tap-highlight-color: rgba(${get('colors.gray.3')}, 0.5); } } +` + +export const tabStyles = css` + flex: 1; + padding: ${get('space.2')}px ${get('space.3')}px; + font-size: ${get('fontSizes.0')}px; + font-weight: 500; + color: ${get('colors.gray.5')}; + text-align: center; + background-color: transparent; + border: 0; + box-shadow: inset 0 -1px 0 ${get('colors.borders.gray')}; + + &:focus { + outline: none; + } + + @media (min-width: ${get('breakpoints.0')}) { + flex: none; + padding: ${get('space.1')}px ${get('space.3')}px; + border: ${get('borders.1')} transparent; + border-bottom-width: 0; + border-top-left-radius: ${get('radii.1')}px; + border-top-right-radius: ${get('radii.1')}px; + } + + &[aria-selected="true"] { + z-index: 1; // Keeps box-shadow visible when hovering + color: ${get('colors.gray.9')}; + background-color: ${get('colors.white')}; + box-shadow: 0 0 0 1px ${get('colors.borders.gray')}; + + @media (min-width: ${get('breakpoints.0')}) { + border-color: ${get('colors.borders.gray')}; + box-shadow: none; + } + } +` + +export const tabWrapperStyles = css` + display: flex; + flex-shrink: 0; + margin-bottom: -1px; // hide border of element below + overflow-x: auto; + overflow-y: hidden; + border-top: ${get('borders.1')} ${get('colors.borders.gray')}; + -webkit-overflow-scrolling: touch; + + // Hide scrollbar so it doesn't cover the text + &::-webkit-scrollbar { + display: none; + } + + @media (min-width: ${get('breakpoints.0')}) { + padding: 0 ${get('space.2')}px; + border-top: 0; + } ` \ No newline at end of file From d2dfcf8977d64c31ca6a1524d5cea2e33bb4fd61 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Mon, 14 Oct 2019 15:56:08 -0700 Subject: [PATCH 012/196] add footer --- docs/content/SelectMenu.md | 13 ++++++++----- src/SelectMenu.js | 12 ++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index 04fee4cf472..69a4257aa1b 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -11,14 +11,17 @@ title: SelectMenu - Users - Repos + Branches + Tags - - - + + + + + + Showing 5 of 5 ``` \ No newline at end of file diff --git a/src/SelectMenu.js b/src/SelectMenu.js index f201af2a4f1..552e6bda24d 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -112,4 +112,16 @@ SelectMenu.Tab = styled.button.attrs(props => ({ ${tabStyles} ` +SelectMenu.Footer = styled.div` + padding: ${get('space.2')}px ${get('space.3')}px; + font-size: ${get('fontSizes.0')}px; + color: ${get('colors.gray.5')}; + text-align: center; + border-top: ${get('borders.1')} ${get('colors.borders.gray')}; + + @media (min-width: ${get('breakpoints.0')}) { + padding: ${get('space.1')}px ${get('space.2')}px; + } +` + export default SelectMenu \ No newline at end of file From 784fef3edeb4be2e8a801f344edc6e1c23328628 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Tue, 15 Oct 2019 12:31:40 -0700 Subject: [PATCH 013/196] add loading state --- docs/content/SelectMenu.md | 26 +++++++++--- src/SelectMenu.js | 79 +++++++++++++++++++++++++++-------- src/SelectMenuStyles.js | 84 +++++++++++++++++++------------------- 3 files changed, 125 insertions(+), 64 deletions(-) diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index 69a4257aa1b..137e857875f 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -15,13 +15,29 @@ title: SelectMenu Tags - - - - - + master + fix-SelectMenu.Item + More options + add-styles + delete-page + hotfix-1 Showing 5 of 5 +``` + +#### With Loading State +```jsx live + + Robots + + + Filter by Author + + + + Loading... + + ``` \ No newline at end of file diff --git a/src/SelectMenu.js b/src/SelectMenu.js index 552e6bda24d..3c9b5c18da7 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -1,11 +1,12 @@ import React from 'react' -import styled from 'styled-components' +import styled, {keyframes} from 'styled-components' import {COMMON, TYPOGRAPHY, get} from './constants' import Button from './Button' import TextInput from './TextInput' import theme from './theme' -import classnames from 'classnames' -import {modalStyles, wrapperStyles, listStyles, tabStyles, tabWrapperStyles} from './SelectMenuStyles' +import StyledOcticon from './StyledOcticon' +import {Octoface} from '@primer/octicons-react' +import {modalStyles, wrapperStyles, listStyles, listItemStyles, tabStyles, tabWrapperStyles} from './SelectMenuStyles' const SelectMenu = styled.details` ${wrapperStyles} @@ -82,21 +83,15 @@ SelectMenu.Filter = (props) => { ) } -const transformChildren = children => { - return React.Children.map(children, child => { - return React.cloneElement(child, {role: 'menuitem', className: classnames(child.props.className, 'SelectMenu--list-item')}) - }) -} - -const StyledList = styled.div` +SelectMenu.Item = styled.button.attrs(props => ({ + role: 'menuitem', + className: 'SelectMenu--list-item' +}))` + ${listItemStyles} +` +SelectMenu.List = styled.div` ${listStyles} ` -SelectMenu.List = ({children, ...rest}) => { - return ( - {transformChildren(children)} - ) -} - SelectMenu.List.defaultProps = { theme } @@ -112,7 +107,7 @@ SelectMenu.Tab = styled.button.attrs(props => ({ ${tabStyles} ` -SelectMenu.Footer = styled.div` +SelectMenu.Footer = styled.footer` padding: ${get('space.2')}px ${get('space.3')}px; font-size: ${get('fontSizes.0')}px; color: ${get('colors.gray.5')}; @@ -124,4 +119,54 @@ SelectMenu.Footer = styled.div` } ` +SelectMenu.Divider = styled.div` + padding: ${get('space.1')}px ${get('space.3')}px; + margin: 0; + font-size: ${get('fontSizes.0')}px; + font-weight: ${get('fontWeights.bold')}; + color: ${get('colors.gray.5')}; + background-color: ${get('colors.gray.1')}; + border-top: ${get('borders.1')} ${get('colors.borders.gray')}; + border-bottom: ${get('borders.1')} ${get('colors.borders.gray')}; + + &:first-child { + border-top: 0; + } + + &:last-child { + border-bottom: 0; + } +` + +const pulseKeyframes = keyframes` + 0% { + opacity: 0.3; + } + + 10% { + opacity: 1; + } + + 100% { + opacity: 0.3; + } +` + +const Animation = styled.div` + padding: ${get('space.4')}px ${get('space.3')}px; + text-align: center; + background-color: ${get('colors.white')}; + animation-name: ${pulseKeyframes}; + animation-duration: 2s; + animation-timing-function: linear; + animation-iteration-count: infinite; +` + +SelectMenu.Loading = () => { + return ( + + + + ) +} export default SelectMenu \ No newline at end of file diff --git a/src/SelectMenuStyles.js b/src/SelectMenuStyles.js index 57cbbb6a176..a71296196b6 100644 --- a/src/SelectMenuStyles.js +++ b/src/SelectMenuStyles.js @@ -104,48 +104,6 @@ export const listStyles = css` border-top: ${get('borders.1')} ${get('colors.borders.gray')}; -webkit-overflow-scrolling: touch; // Adds momentum + bouncy scrolling - .SelectMenu--list-item { - display: flex; - align-items: center; - width: 100%; - padding: ${get('space.3')}px; - overflow: hidden; - color: ${get('colors.gray.6')}; - text-align: left; - cursor: pointer; - background-color: ${get('colors.white')}; - border: 0; - - & + & { - // Add a top border only if the above element also is a list item - border-top: ${get('borders.1')} ${get('colors.gray.2')}; - } - - &:hover { - text-decoration: none; - } - - &:focus { - outline:none; - } - - @media (min-width: ${get('breakpoints.0')}) { - padding-top: ${get('space.2')}px; - padding-bottom: ${get('space.2')}px; - } - } - - .SelectMenu--list-item[aria-checked="true"] { - font-weight: 500; - color: ${get('colors.gray.9')}; - - .SelectMenu-icon { - visibility: visible; - transition: transform 0.12s cubic-bezier(0, 0, 0.2, 1), visibility 0s linear; - transform: scale(1); - } - } - @media (hover: hover) { body:not(.intent-mouse) .SelectMenu--list-item:focus, .SelectMenu--list-item:hover { @@ -248,4 +206,46 @@ export const tabWrapperStyles = css` padding: 0 ${get('space.2')}px; border-top: 0; } +` + +export const listItemStyles = css` + display: flex; + align-items: center; + width: 100%; + padding: ${get('space.3')}px; + overflow: hidden; + color: ${get('colors.gray.6')}; + text-align: left; + cursor: pointer; + background-color: ${get('colors.white')}; + border: 0; + + & + & { + // Add a top border only if the above element also is a list item + border-top: ${get('borders.1')} ${get('colors.gray.2')}; + } + + &:hover { + text-decoration: none; + } + + &:focus { + outline:none; + } + + @media (min-width: ${get('breakpoints.0')}) { + padding-top: ${get('space.2')}px; + padding-bottom: ${get('space.2')}px; + } + + &[aria-checked="true"] { + font-weight: 500; + color: ${get('colors.gray.9')}; + + .SelectMenu-icon { + visibility: visible; + transition: transform 0.12s cubic-bezier(0, 0, 0.2, 1), visibility 0s linear; + transform: scale(1); + } + } ` \ No newline at end of file From 870360a8be214c61a531f53eeaeeda4e153549ce Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Tue, 15 Oct 2019 13:05:02 -0700 Subject: [PATCH 014/196] add checked styles --- src/SelectMenu.js | 13 +++++++++++-- src/SelectMenuStyles.js | 12 +++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/SelectMenu.js b/src/SelectMenu.js index 3c9b5c18da7..06f53817cf7 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -5,7 +5,7 @@ import Button from './Button' import TextInput from './TextInput' import theme from './theme' import StyledOcticon from './StyledOcticon' -import {Octoface} from '@primer/octicons-react' +import {Octoface, Check} from '@primer/octicons-react' import {modalStyles, wrapperStyles, listStyles, listItemStyles, tabStyles, tabWrapperStyles} from './SelectMenuStyles' const SelectMenu = styled.details` @@ -83,7 +83,7 @@ SelectMenu.Filter = (props) => { ) } -SelectMenu.Item = styled.button.attrs(props => ({ +const StyledItem = styled.button.attrs(props => ({ role: 'menuitem', className: 'SelectMenu--list-item' }))` @@ -96,6 +96,15 @@ SelectMenu.List.defaultProps = { theme } +SelectMenu.Item = ({children,...rest}) => { + return ( + + + {children} + + ) +} + SelectMenu.Tabs = styled.nav` ${tabWrapperStyles} ` diff --git a/src/SelectMenuStyles.js b/src/SelectMenuStyles.js index a71296196b6..616077ec864 100644 --- a/src/SelectMenuStyles.js +++ b/src/SelectMenuStyles.js @@ -219,6 +219,7 @@ export const listItemStyles = css` cursor: pointer; background-color: ${get('colors.white')}; border: 0; + line-height: inherit; & + & { // Add a top border only if the above element also is a list item @@ -233,6 +234,15 @@ export const listItemStyles = css` outline:none; } + .SelectMenu-selected { + width: ${get('space.3')}px; // fixed width to make sure following content aligns + margin-right: ${get('space.2')}px; + visibility: hidden; + transition: transform 0.12s cubic-bezier(0.5, 0.1, 1, 0.5), visibility 0s 0.12s linear; + transform: scale(0); + } + + @media (min-width: ${get('breakpoints.0')}) { padding-top: ${get('space.2')}px; padding-bottom: ${get('space.2')}px; @@ -242,7 +252,7 @@ export const listItemStyles = css` font-weight: 500; color: ${get('colors.gray.9')}; - .SelectMenu-icon { + .SelectMenu-selected { visibility: visible; transition: transform 0.12s cubic-bezier(0, 0, 0.2, 1), visibility 0s linear; transform: scale(1); From 0700fcc84a3781b0ee5da7a3bcf51d23db9eaf82 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Tue, 15 Oct 2019 14:23:33 -0700 Subject: [PATCH 015/196] add Animation component --- docs/content/Animations.md | 17 ++++++++++ .../gatsby-theme-doctocat/live-code-scope.js | 4 +-- .../src/@primer/gatsby-theme-doctocat/nav.yml | 2 ++ src/Animations.js | 33 +++++++++++++++++++ 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 docs/content/Animations.md create mode 100644 src/Animations.js diff --git a/docs/content/Animations.md b/docs/content/Animations.md new file mode 100644 index 00000000000..2446b9d8e2d --- /dev/null +++ b/docs/content/Animations.md @@ -0,0 +1,17 @@ +--- +title: Animations +--- + +Use Animation helper components to provide animations to UI. + + +```jsx live + + + +``` + +## System props + +Animation components get `COMMON` system props. Read our [System Props](/system-props) doc page for a full list of available props. + diff --git a/docs/src/@primer/gatsby-theme-doctocat/live-code-scope.js b/docs/src/@primer/gatsby-theme-doctocat/live-code-scope.js index fbd542ee454..9935a95e4ee 100644 --- a/docs/src/@primer/gatsby-theme-doctocat/live-code-scope.js +++ b/docs/src/@primer/gatsby-theme-doctocat/live-code-scope.js @@ -1,6 +1,6 @@ import * as primerComponents from '@primer/components' import * as doctocatComponents from '@primer/gatsby-theme-doctocat' -import Octicon, {Check, Zap, X} from '@primer/octicons-react' +import Octicon, {Check, Zap, X, Octoface} from '@primer/octicons-react' import State from '../../../components/State' -export default {...primerComponents, ...doctocatComponents, State, Octicon, Check, Zap, X} +export default {...primerComponents, ...doctocatComponents, State, Octicon, Check, Octoface, Zap, X} diff --git a/docs/src/@primer/gatsby-theme-doctocat/nav.yml b/docs/src/@primer/gatsby-theme-doctocat/nav.yml index 874b91e1d3b..e271f138a32 100644 --- a/docs/src/@primer/gatsby-theme-doctocat/nav.yml +++ b/docs/src/@primer/gatsby-theme-doctocat/nav.yml @@ -12,6 +12,8 @@ - title: Components children: + - title: Animations + url: /Animations - title: Avatar url: /Avatar - title: BorderBox diff --git a/src/Animations.js b/src/Animations.js new file mode 100644 index 00000000000..c60136b959c --- /dev/null +++ b/src/Animations.js @@ -0,0 +1,33 @@ +import styled, {keyframes} from 'styled-components' +import {COMMON} from './constants' +import theme from './theme' + +let Animations = {} + +const pulseKeyframes = keyframes` + 0% { + opacity: 0.3; + } + + 10% { + opacity: 1; + } + + 100% { + opacity: 0.3; + } +` + +Animations.Pulse = styled.span` + animation-name: ${pulseKeyframes}; + animation-duration: 2s; + animation-timing-function: linear; + animation-iteration-count: infinite; + ${COMMON} +` + +Animations.Pulse.defaultProps = { + theme +} + +export default Animations \ No newline at end of file From 8a8678144b40089d7c48be43a21a66c17215ed2c Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Tue, 15 Oct 2019 14:23:43 -0700 Subject: [PATCH 016/196] refactor --- src/SelectMenu.js | 65 +++++++---------------------------------- src/SelectMenuStyles.js | 31 ++++++++++++++++++++ src/index.js | 1 + 3 files changed, 43 insertions(+), 54 deletions(-) diff --git a/src/SelectMenu.js b/src/SelectMenu.js index 06f53817cf7..bfa07b301d0 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -1,12 +1,14 @@ import React from 'react' -import styled, {keyframes} from 'styled-components' +import styled from 'styled-components' import {COMMON, TYPOGRAPHY, get} from './constants' import Button from './Button' +import Box from './Box' import TextInput from './TextInput' import theme from './theme' import StyledOcticon from './StyledOcticon' import {Octoface, Check} from '@primer/octicons-react' -import {modalStyles, wrapperStyles, listStyles, listItemStyles, tabStyles, tabWrapperStyles} from './SelectMenuStyles' +import Animations from './Animations' +import {modalStyles, wrapperStyles, dividerStyles, footerStyles, listStyles, listItemStyles, tabStyles, tabWrapperStyles} from './SelectMenuStyles' const SelectMenu = styled.details` ${wrapperStyles} @@ -117,65 +119,20 @@ SelectMenu.Tab = styled.button.attrs(props => ({ ` SelectMenu.Footer = styled.footer` - padding: ${get('space.2')}px ${get('space.3')}px; - font-size: ${get('fontSizes.0')}px; - color: ${get('colors.gray.5')}; - text-align: center; - border-top: ${get('borders.1')} ${get('colors.borders.gray')}; - - @media (min-width: ${get('breakpoints.0')}) { - padding: ${get('space.1')}px ${get('space.2')}px; - } + ${footerStyles} ` SelectMenu.Divider = styled.div` - padding: ${get('space.1')}px ${get('space.3')}px; - margin: 0; - font-size: ${get('fontSizes.0')}px; - font-weight: ${get('fontWeights.bold')}; - color: ${get('colors.gray.5')}; - background-color: ${get('colors.gray.1')}; - border-top: ${get('borders.1')} ${get('colors.borders.gray')}; - border-bottom: ${get('borders.1')} ${get('colors.borders.gray')}; - - &:first-child { - border-top: 0; - } - - &:last-child { - border-bottom: 0; - } -` - -const pulseKeyframes = keyframes` - 0% { - opacity: 0.3; - } - - 10% { - opacity: 1; - } - - 100% { - opacity: 0.3; - } -` - -const Animation = styled.div` - padding: ${get('space.4')}px ${get('space.3')}px; - text-align: center; - background-color: ${get('colors.white')}; - animation-name: ${pulseKeyframes}; - animation-duration: 2s; - animation-timing-function: linear; - animation-iteration-count: infinite; + ${dividerStyles} ` SelectMenu.Loading = () => { return ( - - - + + + + + ) } export default SelectMenu \ No newline at end of file diff --git a/src/SelectMenuStyles.js b/src/SelectMenuStyles.js index 616077ec864..20357f6f3a0 100644 --- a/src/SelectMenuStyles.js +++ b/src/SelectMenuStyles.js @@ -258,4 +258,35 @@ export const listItemStyles = css` transform: scale(1); } } +` + +export const footerStyles = css` + padding: ${get('space.2')}px ${get('space.3')}px; + font-size: ${get('fontSizes.0')}px; + color: ${get('colors.gray.5')}; + text-align: center; + border-top: ${get('borders.1')} ${get('colors.borders.gray')}; + + @media (min-width: ${get('breakpoints.0')}) { + padding: ${get('space.1')}px ${get('space.2')}px; + } +` + +export const dividerStyles = css` + padding: ${get('space.1')}px ${get('space.3')}px; + margin: 0; + font-size: ${get('fontSizes.0')}px; + font-weight: ${get('fontWeights.bold')}; + color: ${get('colors.gray.5')}; + background-color: ${get('colors.gray.1')}; + border-top: ${get('borders.1')} ${get('colors.borders.gray')}; + border-bottom: ${get('borders.1')} ${get('colors.borders.gray')}; + + &:first-child { + border-top: 0; + } + + &:last-child { + border-bottom: 0; + } ` \ No newline at end of file diff --git a/src/index.js b/src/index.js index b3a9435cdce..e55410a58ca 100644 --- a/src/index.js +++ b/src/index.js @@ -10,6 +10,7 @@ export {default as Grid} from './Grid' export {Position, Absolute, Fixed, Relative, Sticky} from './Position' // Components +export {default as Animations} from './Animations' export {default as Avatar} from './Avatar' export {default as AvatarPair} from './AvatarPair' export {default as BranchName} from './BranchName' From bedca125cf5a0c03cbcdf9f843157ad819e9852f Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Tue, 15 Oct 2019 14:55:37 -0700 Subject: [PATCH 017/196] move into separate files --- src/SelectMenu.js | 156 +++++++-------------------------------- src/SelectMenuDivider.js | 15 ++++ src/SelectMenuFilter.js | 30 ++++++++ src/SelectMenuFooter.js | 15 ++++ src/SelectMenuHeader.js | 21 ++++++ src/SelectMenuItem.js | 30 ++++++++ src/SelectMenuList.js | 12 +++ src/SelectMenuLoading.js | 16 ++++ src/SelectMenuModal.js | 26 +++++++ src/SelectMenuSummary.js | 4 + src/SelectMenuTab.js | 18 +++++ src/SelectMenuTabs.js | 15 ++++ src/SelectMenuTitle.js | 22 ++++++ 13 files changed, 250 insertions(+), 130 deletions(-) create mode 100644 src/SelectMenuDivider.js create mode 100644 src/SelectMenuFilter.js create mode 100644 src/SelectMenuFooter.js create mode 100644 src/SelectMenuHeader.js create mode 100644 src/SelectMenuItem.js create mode 100644 src/SelectMenuList.js create mode 100644 src/SelectMenuLoading.js create mode 100644 src/SelectMenuModal.js create mode 100644 src/SelectMenuSummary.js create mode 100644 src/SelectMenuTab.js create mode 100644 src/SelectMenuTabs.js create mode 100644 src/SelectMenuTitle.js diff --git a/src/SelectMenu.js b/src/SelectMenu.js index bfa07b301d0..5a189bed07c 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -1,138 +1,34 @@ -import React from 'react' import styled from 'styled-components' -import {COMMON, TYPOGRAPHY, get} from './constants' -import Button from './Button' -import Box from './Box' -import TextInput from './TextInput' -import theme from './theme' -import StyledOcticon from './StyledOcticon' -import {Octoface, Check} from '@primer/octicons-react' -import Animations from './Animations' -import {modalStyles, wrapperStyles, dividerStyles, footerStyles, listStyles, listItemStyles, tabStyles, tabWrapperStyles} from './SelectMenuStyles' +import {COMMON} from './constants' +import {wrapperStyles} from './SelectMenuStyles' +import SelectMenuDivider from './SelectMenuDivider' +import SelectMenuFilter from './SelectMenuFilter' +import SelectMenuFooter from './SelectMenuFooter' +import SelectMenuHeader from './SelectMenuHeader' +import SelectMenuItem from './SelectMenuItem' +import SelectMenuList from './SelectMenuList' +import SelectMenuLoading from './SelectMenuLoading' +import SelectMenuModal from './SelectMenuModal' +import SelectMenuSummary from './SelectMenuSummary' +import SelectMenuTab from './SelectMenuTab' +import SelectMenuTabs from './SelectMenuTabs' +import SelectMenuTitle from './SelectMenuTitle' const SelectMenu = styled.details` ${wrapperStyles} ${COMMON} ` +SelectMenu.Divider = SelectMenuDivider +SelectMenu.Filter = SelectMenuFilter +SelectMenu.Footer = SelectMenuFooter +SelectMenu.Header = SelectMenuHeader +SelectMenu.Item = SelectMenuItem +SelectMenu.List = SelectMenuList +SelectMenu.Loading = SelectMenuLoading +SelectMenu.Modal = SelectMenuModal +SelectMenu.Summary = SelectMenuSummary +SelectMenu.Tabs = SelectMenuTabs +SelectMenu.Tab = SelectMenuTab +SelectMenu.Title = SelectMenuTitle -const ModalWrapper = styled.div` - ${modalStyles} -` - -SelectMenu.Summary = ({children, ...rest}) => - -SelectMenu.Modal = ({children, filter, theme}) => { - return ( - - - {children} - - - ) -} - -SelectMenu.Modal.defaultProps = { - theme -} - -SelectMenu.Header = styled.header` - display: flex; - flex: none; // fixes header from getting squeezed in Safari iOS - padding: ${get('space.3')}px; - - @media (min-width: ${get('breakpoints.0')}) { - padding-top: ${get('space.2')}px; - padding-bottom: ${get('space.2')}px; - } -` - -SelectMenu.Header.defaultProps = { - theme -} - -SelectMenu.Title = styled.h3` - flex: auto; - font-size: ${get('fontSizes.1')}px; - font-weight: ${get('fontWeights.bold')}; - margin: 0; - ${COMMON} - ${TYPOGRAPHY} - - @media (min-width: ${get('breakpoints.0')}) { - font-size: inherit; - } -` - -SelectMenu.Title.defaultProps = { - theme -} - -const StyledForm = styled.form` - padding: ${get('space.3')}px; - margin: 0; - border-top: ${get('borders.1')} ${get('colors.borders.gray')}; - - @media (min-width: ${get('breakpoints.0')}) { - padding: ${get('space.2')}px; - } -` - -SelectMenu.Filter = (props) => { - return ( - - - - ) -} - -const StyledItem = styled.button.attrs(props => ({ - role: 'menuitem', - className: 'SelectMenu--list-item' -}))` - ${listItemStyles} -` -SelectMenu.List = styled.div` - ${listStyles} -` -SelectMenu.List.defaultProps = { - theme -} - -SelectMenu.Item = ({children,...rest}) => { - return ( - - - {children} - - ) -} - -SelectMenu.Tabs = styled.nav` - ${tabWrapperStyles} -` - -SelectMenu.Tab = styled.button.attrs(props => ({ - className: 'SelectMenuTab', - "aria-selected": props.selected -}))` - ${tabStyles} -` - -SelectMenu.Footer = styled.footer` - ${footerStyles} -` - -SelectMenu.Divider = styled.div` - ${dividerStyles} -` - -SelectMenu.Loading = () => { - return ( - - - - - - ) -} export default SelectMenu \ No newline at end of file diff --git a/src/SelectMenuDivider.js b/src/SelectMenuDivider.js new file mode 100644 index 00000000000..e137b0fdc2e --- /dev/null +++ b/src/SelectMenuDivider.js @@ -0,0 +1,15 @@ +import styled from 'styled-components' +import {dividerStyles} from './SelectMenuStyles' +import theme from './theme' +import {COMMON} from './constants' + +const SelectMenuDivider = styled.div` + ${dividerStyles} + ${COMMON} +` + +SelectMenuDivider.defaultProps = { + theme +} + +export default SelectMenuDivider \ No newline at end of file diff --git a/src/SelectMenuFilter.js b/src/SelectMenuFilter.js new file mode 100644 index 00000000000..9b15d653cb8 --- /dev/null +++ b/src/SelectMenuFilter.js @@ -0,0 +1,30 @@ +import React from 'react' +import styled from 'styled-components' +import {COMMON, get} from './constants' +import theme from './theme' +import TextInput from './TextInput' + +const StyledForm = styled.form` + padding: ${get('space.3')}px; + margin: 0; + border-top: ${get('borders.1')} ${get('colors.borders.gray')}; + ${COMMON} + + @media (min-width: ${get('breakpoints.0')}) { + padding: ${get('space.2')}px; + } +` + +const SelectMenuFilter = (props) => { + return ( + + + + ) +} + +SelectMenuFilter.defaultProps = { + theme +} + +export default SelectMenuFilter \ No newline at end of file diff --git a/src/SelectMenuFooter.js b/src/SelectMenuFooter.js new file mode 100644 index 00000000000..323e9fbb473 --- /dev/null +++ b/src/SelectMenuFooter.js @@ -0,0 +1,15 @@ +import styled from 'styled-components' +import {footerStyles} from './SelectMenuStyles' +import {COMMON} from './constants' +import theme from './theme' + +const SelectMenuFooter = styled.footer` + ${footerStyles} + ${COMMON} +` + +SelectMenuFooter.defaultProps = { + theme +} + +export default SelectMenuFooter \ No newline at end of file diff --git a/src/SelectMenuHeader.js b/src/SelectMenuHeader.js new file mode 100644 index 00000000000..0c4d716b731 --- /dev/null +++ b/src/SelectMenuHeader.js @@ -0,0 +1,21 @@ +import styled from 'styled-components' +import {get, COMMON} from './constants' +import theme from './theme' + +const SelectMenuHeader = styled.header` + display: flex; + flex: none; // fixes header from getting squeezed in Safari iOS + padding: ${get('space.3')}px; + ${COMMON} + + @media (min-width: ${get('breakpoints.0')}) { + padding-top: ${get('space.2')}px; + padding-bottom: ${get('space.2')}px; + } +` + +SelectMenuHeader.defaultProps = { + theme +} + +export default SelectMenuHeader \ No newline at end of file diff --git a/src/SelectMenuItem.js b/src/SelectMenuItem.js new file mode 100644 index 00000000000..558a58999d1 --- /dev/null +++ b/src/SelectMenuItem.js @@ -0,0 +1,30 @@ +import React from 'react' +import styled from 'styled-components' +import {Check} from '@primer/octicons-react' +import {listItemStyles} from './SelectMenuStyles' +import {COMMON} from './constants' +import StyledOcticon from './StyledOcticon' +import theme from './theme' + +const StyledItem = styled.button.attrs(props => ({ + role: 'menuitem', + className: 'SelectMenu--list-item' +}))` + ${listItemStyles} + ${COMMON} +` + +const SelectMenuItem = ({children,...rest}) => { + return ( + + + {children} + + ) +} + +SelectMenuItem.defaultProps = { + theme +} + +export default SelectMenuItem \ No newline at end of file diff --git a/src/SelectMenuList.js b/src/SelectMenuList.js new file mode 100644 index 00000000000..1aa933cea96 --- /dev/null +++ b/src/SelectMenuList.js @@ -0,0 +1,12 @@ +import styled from 'styled-components' +import {listStyles} from './SelectMenuStyles' +import theme from './theme' + +const SelectMenuList = styled.div` + ${listStyles} +` +SelectMenuList.defaultProps = { + theme +} + +export default SelectMenuList \ No newline at end of file diff --git a/src/SelectMenuLoading.js b/src/SelectMenuLoading.js new file mode 100644 index 00000000000..2d601466161 --- /dev/null +++ b/src/SelectMenuLoading.js @@ -0,0 +1,16 @@ +import React from 'react' +import Box from './Box' +import Animations from './Animations' +import StyledOcticon, {Octoface} from '@primer/octicons-react' + +const SelectMenuLoading = (props) => { + return ( + + + + + + ) +} + +export default SelectMenuLoading \ No newline at end of file diff --git a/src/SelectMenuModal.js b/src/SelectMenuModal.js new file mode 100644 index 00000000000..eda52ed3a41 --- /dev/null +++ b/src/SelectMenuModal.js @@ -0,0 +1,26 @@ +import React from 'react' +import styled from 'styled-components' +import {COMMON} from './constants' +import {modalStyles} from './SelectMenuStyles' +import theme from './theme' + +const ModalWrapper = styled.div` + ${modalStyles} + ${COMMON} +` + +const SelectMenuModal = ({children,...rest}) => { + return ( + + + {children} + + + ) +} + +SelectMenuModal.defaultProps = { + theme +} + +export default SelectMenuModal \ No newline at end of file diff --git a/src/SelectMenuSummary.js b/src/SelectMenuSummary.js new file mode 100644 index 00000000000..3e3f936687b --- /dev/null +++ b/src/SelectMenuSummary.js @@ -0,0 +1,4 @@ +import React from 'react' +import Button from './Button' + +export default ({children, ...rest}) => diff --git a/src/SelectMenuTab.js b/src/SelectMenuTab.js new file mode 100644 index 00000000000..4222920e3e3 --- /dev/null +++ b/src/SelectMenuTab.js @@ -0,0 +1,18 @@ +import styled from 'styled-components' +import {tabStyles} from './SelectMenuStyles' +import theme from './theme' +import {COMMON} from './constants' + +const SelectMenuTab = styled.button.attrs(props => ({ + className: 'SelectMenuTab', + "aria-selected": props.selected +}))` + ${tabStyles} + ${COMMON} +` + +SelectMenuTab.defaultProps = { + theme +} + +export default SelectMenuTab \ No newline at end of file diff --git a/src/SelectMenuTabs.js b/src/SelectMenuTabs.js new file mode 100644 index 00000000000..251bd91c281 --- /dev/null +++ b/src/SelectMenuTabs.js @@ -0,0 +1,15 @@ +import styled from 'styled-components' +import {tabWrapperStyles} from './SelectMenuStyles' +import {COMMON} from './constants' +import theme from './theme' + +const SelectMenuTabs = styled.nav` + ${tabWrapperStyles} + ${COMMON} +` + +SelectMenuTabs.defaultProps = { + theme +} + +export default SelectMenuTabs \ No newline at end of file diff --git a/src/SelectMenuTitle.js b/src/SelectMenuTitle.js new file mode 100644 index 00000000000..ac9ebd766fc --- /dev/null +++ b/src/SelectMenuTitle.js @@ -0,0 +1,22 @@ +import styled from 'styled-components' +import {COMMON, TYPOGRAPHY, get} from './constants' +import theme from './theme' + +const SelectMenuTitle = styled.h3` + flex: auto; + font-size: ${get('fontSizes.1')}px; + font-weight: ${get('fontWeights.bold')}; + margin: 0; + ${COMMON} + ${TYPOGRAPHY} + + @media (min-width: ${get('breakpoints.0')}) { + font-size: inherit; + } +` + +SelectMenuTitle.defaultProps = { + theme +} + +export default SelectMenuTitle \ No newline at end of file From c7e70b1657c2fa46107c7c7e35b34c1969c81afb Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Tue, 15 Oct 2019 15:56:38 -0700 Subject: [PATCH 018/196] tabs refactoring --- docs/content/SelectMenu.md | 21 +++++++++++---------- src/SelectMenuTab.js | 9 ++++++++- src/SelectMenuTabs.js | 4 +++- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index 137e857875f..d79e8dc0aaa 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -7,22 +7,23 @@ title: SelectMenu Robots - Filter by Author + Filter by project - + - Branches - Tags + Repository + Organization - master - fix-SelectMenu.Item + Primer Components release tracking + Primer Compononents roadmap More options - add-styles - delete-page - hotfix-1 + Primer Components bugs + + - Showing 5 of 5 + Showing 3 of 3 ``` diff --git a/src/SelectMenuTab.js b/src/SelectMenuTab.js index 4222920e3e3..8b4f5ad6e7b 100644 --- a/src/SelectMenuTab.js +++ b/src/SelectMenuTab.js @@ -1,10 +1,12 @@ import styled from 'styled-components' +import PropTypes from 'prop-types' import {tabStyles} from './SelectMenuStyles' import theme from './theme' import {COMMON} from './constants' const SelectMenuTab = styled.button.attrs(props => ({ className: 'SelectMenuTab', + role: 'tab', "aria-selected": props.selected }))` ${tabStyles} @@ -12,7 +14,12 @@ const SelectMenuTab = styled.button.attrs(props => ({ ` SelectMenuTab.defaultProps = { - theme + theme, + selected: false +} + +SelectMenuTab.propTypes = { + selected: PropTypes.bool, } export default SelectMenuTab \ No newline at end of file diff --git a/src/SelectMenuTabs.js b/src/SelectMenuTabs.js index 251bd91c281..7995da895f2 100644 --- a/src/SelectMenuTabs.js +++ b/src/SelectMenuTabs.js @@ -3,7 +3,9 @@ import {tabWrapperStyles} from './SelectMenuStyles' import {COMMON} from './constants' import theme from './theme' -const SelectMenuTabs = styled.nav` +const SelectMenuTabs = styled.nav.attrs({ + role: 'tablist' +})` ${tabWrapperStyles} ${COMMON} ` From 7be9d9a759e7058604a356d5f2d91cee051fe759 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Tue, 15 Oct 2019 16:12:59 -0700 Subject: [PATCH 019/196] first pass at documentation --- docs/content/SelectMenu.md | 50 ++++++++++++++++++++++++++++++++------ src/SelectMenu.js | 2 -- src/SelectMenuHeader.js | 30 +++++++++++++++++++++-- 3 files changed, 71 insertions(+), 11 deletions(-) diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index d79e8dc0aaa..bd00016b252 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -6,9 +6,7 @@ title: SelectMenu Robots - - Filter by project - + Filter by project Repository @@ -33,12 +31,50 @@ title: SelectMenu Robots - - Filter by Author - + Filter by Author Loading... -``` \ No newline at end of file +``` + +### SelectMenu +Used as a wrapper component for select menus + +### SelectMenu.Summary +Used as the trigger component for the SelectMenu dropdown. Must be used with `SelectMenu` and `SelectMenu.Modal` + +### SelectMenu.Modal +Provides styling for the SelectMenu content + +### SelectMenu.Header +A heading for the SelectMenu + +### SelectMenu.Loading +A default loading state for the SelectMenu contents + +### SelectMenu.Footer +A footer for the SelectMenu + +### SelectMenu.Tabs +Tab navigation for the SelectMenu + +### SelectMenu.Tab +Individual tabs for the tab navigation in SelectMenu. `selected` state should be handled in consuming application and passed down via the `selected` prop to get styling. + +| Name | Type | Default | Description | +| :- | :- | :-: | :- | +| selected | Boolean | false | Used to style the selected tab. + +### SelectMenu.List + +Wrapper around SelectMenu items. Use multiple `SelectMenu.List` components when using tab navigation within the select menu. Handle selected tab state in the consuming application and dynamically apple the `hidden` HTML attribute on the list to hide unselected tabs. + +| Name | Type | Default | Description | +| :- | :- | :-: | :- | +| hidden | Boolean | false| Sets the HTML hidden attribute, used when you'd like to hide panels for tab navigation within a SelectMenu + +### SelectMenu.Divider +Used to create a divider between list items + diff --git a/src/SelectMenu.js b/src/SelectMenu.js index 5a189bed07c..7db6832082b 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -12,7 +12,6 @@ import SelectMenuModal from './SelectMenuModal' import SelectMenuSummary from './SelectMenuSummary' import SelectMenuTab from './SelectMenuTab' import SelectMenuTabs from './SelectMenuTabs' -import SelectMenuTitle from './SelectMenuTitle' const SelectMenu = styled.details` ${wrapperStyles} @@ -29,6 +28,5 @@ SelectMenu.Modal = SelectMenuModal SelectMenu.Summary = SelectMenuSummary SelectMenu.Tabs = SelectMenuTabs SelectMenu.Tab = SelectMenuTab -SelectMenu.Title = SelectMenuTitle export default SelectMenu \ No newline at end of file diff --git a/src/SelectMenuHeader.js b/src/SelectMenuHeader.js index 0c4d716b731..57bc702ab49 100644 --- a/src/SelectMenuHeader.js +++ b/src/SelectMenuHeader.js @@ -1,18 +1,44 @@ +import React from 'react' import styled from 'styled-components' -import {get, COMMON} from './constants' +import {get, COMMON, TYPOGRAPHY} from './constants' import theme from './theme' -const SelectMenuHeader = styled.header` +const SelectMenuTitle = styled.h3` + flex: auto; + font-size: ${get('fontSizes.1')}px; + font-weight: ${get('fontWeights.bold')}; + margin: 0; + + @media (min-width: ${get('breakpoints.0')}) { + font-size: inherit; + } +` + +SelectMenuTitle.defaultProps = { + theme +} + +const StyledHeader = styled.header` display: flex; flex: none; // fixes header from getting squeezed in Safari iOS padding: ${get('space.3')}px; ${COMMON} + ${TYPOGRAPHY} @media (min-width: ${get('breakpoints.0')}) { padding-top: ${get('space.2')}px; padding-bottom: ${get('space.2')}px; } ` +const SelectMenuHeader = ({children, ...rest}) => { + return ( + + + {children} + + + ) +} SelectMenuHeader.defaultProps = { theme From 6ae68d2c960f16342f6e7da6218159ff39f48808 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 16 Oct 2019 08:47:43 -0700 Subject: [PATCH 020/196] add SelectMenu.Item docs --- docs/content/SelectMenu.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index bd00016b252..11259457e97 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -48,6 +48,18 @@ Used as the trigger component for the SelectMenu dropdown. Must be used with `Se ### SelectMenu.Modal Provides styling for the SelectMenu content +### SelectMenu.List + +Wrapper around SelectMenu items. Use multiple `SelectMenu.List` components when using tab navigation within the select menu. Handle selected tab state in the consuming application and dynamically apple the `hidden` HTML attribute on the list to hide unselected tabs. + +| Name | Type | Default | Description | +| :- | :- | :-: | :- | +| hidden | Boolean | false| Sets the HTML hidden attribute, used when you'd like to hide panels for tab navigation within a SelectMenu + +### SelectMenu.Item + +Items in the SelectMenu.List. Handle setting the `aria-checked` attribute in the consuming application. When `aria-checked` is set to true, selected styles will appear for list items. + ### SelectMenu.Header A heading for the SelectMenu @@ -67,14 +79,6 @@ Individual tabs for the tab navigation in SelectMenu. `selected` state should be | :- | :- | :-: | :- | | selected | Boolean | false | Used to style the selected tab. -### SelectMenu.List - -Wrapper around SelectMenu items. Use multiple `SelectMenu.List` components when using tab navigation within the select menu. Handle selected tab state in the consuming application and dynamically apple the `hidden` HTML attribute on the list to hide unselected tabs. - -| Name | Type | Default | Description | -| :- | :- | :-: | :- | -| hidden | Boolean | false| Sets the HTML hidden attribute, used when you'd like to hide panels for tab navigation within a SelectMenu - ### SelectMenu.Divider Used to create a divider between list items From a75cb7f64b3e5c75fca91c345fc24889a2c9b19b Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 16 Oct 2019 08:49:20 -0700 Subject: [PATCH 021/196] update docs --- docs/content/SelectMenu.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index 11259457e97..b2439cf6114 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -13,7 +13,7 @@ title: SelectMenu Organization - Primer Components release tracking + Primer Components release tracking Primer Compononents roadmap More options Primer Components bugs From bc7bfefc9824a9cc1139c43fb82b13ec33ce78db Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 16 Oct 2019 08:50:11 -0700 Subject: [PATCH 022/196] typo --- docs/content/SelectMenu.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index b2439cf6114..dd4f9671d8f 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -50,7 +50,7 @@ Provides styling for the SelectMenu content ### SelectMenu.List -Wrapper around SelectMenu items. Use multiple `SelectMenu.List` components when using tab navigation within the select menu. Handle selected tab state in the consuming application and dynamically apple the `hidden` HTML attribute on the list to hide unselected tabs. +Wrapper around SelectMenu items. Use multiple `SelectMenu.List` components when using tab navigation within the select menu. Handle selected tab state in the consuming application and dynamically apply the `hidden` HTML attribute on the list to hide unselected tabs. | Name | Type | Default | Description | | :- | :- | :-: | :- | From 8239ba40f3add860f267b8b278f75c45ecdd3a5d Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 16 Oct 2019 15:15:14 -0700 Subject: [PATCH 023/196] lint & snapshots --- src/Animations.js | 4 +- src/SelectMenu.js | 2 +- src/SelectMenuDivider.js | 2 +- src/SelectMenuFilter.js | 6 +- src/SelectMenuFooter.js | 2 +- src/SelectMenuHeader.js | 6 +- src/SelectMenuItem.js | 8 +- src/SelectMenuList.js | 2 +- src/SelectMenuLoading.js | 8 +- src/SelectMenuModal.js | 6 +- src/SelectMenuStyles.js | 39 ++++---- src/SelectMenuSummary.js | 8 +- src/SelectMenuTab.js | 6 +- src/SelectMenuTabs.js | 2 +- src/SelectMenuTitle.js | 2 +- src/TextInput.js | 2 +- .../__snapshots__/FilterListItem.js.snap | 4 + src/__tests__/__snapshots__/TextInput.js.snap | 96 ++++--------------- .../__snapshots__/UnderlineNavLink.js.snap | 4 + 19 files changed, 81 insertions(+), 128 deletions(-) diff --git a/src/Animations.js b/src/Animations.js index c60136b959c..3f51e39cc11 100644 --- a/src/Animations.js +++ b/src/Animations.js @@ -2,7 +2,7 @@ import styled, {keyframes} from 'styled-components' import {COMMON} from './constants' import theme from './theme' -let Animations = {} +const Animations = {} const pulseKeyframes = keyframes` 0% { @@ -30,4 +30,4 @@ Animations.Pulse.defaultProps = { theme } -export default Animations \ No newline at end of file +export default Animations diff --git a/src/SelectMenu.js b/src/SelectMenu.js index 7db6832082b..a211db407ad 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -29,4 +29,4 @@ SelectMenu.Summary = SelectMenuSummary SelectMenu.Tabs = SelectMenuTabs SelectMenu.Tab = SelectMenuTab -export default SelectMenu \ No newline at end of file +export default SelectMenu diff --git a/src/SelectMenuDivider.js b/src/SelectMenuDivider.js index e137b0fdc2e..3af8a74127a 100644 --- a/src/SelectMenuDivider.js +++ b/src/SelectMenuDivider.js @@ -12,4 +12,4 @@ SelectMenuDivider.defaultProps = { theme } -export default SelectMenuDivider \ No newline at end of file +export default SelectMenuDivider diff --git a/src/SelectMenuFilter.js b/src/SelectMenuFilter.js index 9b15d653cb8..29b51571af8 100644 --- a/src/SelectMenuFilter.js +++ b/src/SelectMenuFilter.js @@ -15,10 +15,10 @@ const StyledForm = styled.form` } ` -const SelectMenuFilter = (props) => { +const SelectMenuFilter = props => { return ( - + ) } @@ -27,4 +27,4 @@ SelectMenuFilter.defaultProps = { theme } -export default SelectMenuFilter \ No newline at end of file +export default SelectMenuFilter diff --git a/src/SelectMenuFooter.js b/src/SelectMenuFooter.js index 323e9fbb473..a59ee2005c8 100644 --- a/src/SelectMenuFooter.js +++ b/src/SelectMenuFooter.js @@ -12,4 +12,4 @@ SelectMenuFooter.defaultProps = { theme } -export default SelectMenuFooter \ No newline at end of file +export default SelectMenuFooter diff --git a/src/SelectMenuHeader.js b/src/SelectMenuHeader.js index 57bc702ab49..85b4192bd29 100644 --- a/src/SelectMenuHeader.js +++ b/src/SelectMenuHeader.js @@ -33,9 +33,7 @@ const StyledHeader = styled.header` const SelectMenuHeader = ({children, ...rest}) => { return ( - - {children} - + {children} ) } @@ -44,4 +42,4 @@ SelectMenuHeader.defaultProps = { theme } -export default SelectMenuHeader \ No newline at end of file +export default SelectMenuHeader diff --git a/src/SelectMenuItem.js b/src/SelectMenuItem.js index 558a58999d1..734a8332f61 100644 --- a/src/SelectMenuItem.js +++ b/src/SelectMenuItem.js @@ -6,7 +6,7 @@ import {COMMON} from './constants' import StyledOcticon from './StyledOcticon' import theme from './theme' -const StyledItem = styled.button.attrs(props => ({ +const StyledItem = styled.button.attrs(() => ({ role: 'menuitem', className: 'SelectMenu--list-item' }))` @@ -14,10 +14,10 @@ const StyledItem = styled.button.attrs(props => ({ ${COMMON} ` -const SelectMenuItem = ({children,...rest}) => { +const SelectMenuItem = ({children, ...rest}) => { return ( - + {children} ) @@ -27,4 +27,4 @@ SelectMenuItem.defaultProps = { theme } -export default SelectMenuItem \ No newline at end of file +export default SelectMenuItem diff --git a/src/SelectMenuList.js b/src/SelectMenuList.js index 1aa933cea96..68cea3885ce 100644 --- a/src/SelectMenuList.js +++ b/src/SelectMenuList.js @@ -9,4 +9,4 @@ SelectMenuList.defaultProps = { theme } -export default SelectMenuList \ No newline at end of file +export default SelectMenuList diff --git a/src/SelectMenuLoading.js b/src/SelectMenuLoading.js index 2d601466161..6aa6db56b29 100644 --- a/src/SelectMenuLoading.js +++ b/src/SelectMenuLoading.js @@ -3,14 +3,14 @@ import Box from './Box' import Animations from './Animations' import StyledOcticon, {Octoface} from '@primer/octicons-react' -const SelectMenuLoading = (props) => { +const SelectMenuLoading = props => { return ( - + - + ) } -export default SelectMenuLoading \ No newline at end of file +export default SelectMenuLoading diff --git a/src/SelectMenuModal.js b/src/SelectMenuModal.js index eda52ed3a41..23fcf21aa49 100644 --- a/src/SelectMenuModal.js +++ b/src/SelectMenuModal.js @@ -9,10 +9,10 @@ const ModalWrapper = styled.div` ${COMMON} ` -const SelectMenuModal = ({children,...rest}) => { +const SelectMenuModal = ({children, ...rest}) => { return ( - + {children} @@ -23,4 +23,4 @@ SelectMenuModal.defaultProps = { theme } -export default SelectMenuModal \ No newline at end of file +export default SelectMenuModal diff --git a/src/SelectMenuStyles.js b/src/SelectMenuStyles.js index 20357f6f3a0..8aee4d153d1 100644 --- a/src/SelectMenuStyles.js +++ b/src/SelectMenuStyles.js @@ -26,7 +26,7 @@ export const modalStyles = css` bottom: 0; left: 0; pointer-events: none; - content: ""; + content: ''; background-color: ${get('colors.blackfade50')}; @media (min-width: ${get('breakpoints.0')}) { @@ -38,10 +38,10 @@ export const modalStyles = css` position: relative; z-index: 99; // Needs to be higher than .details-overlay's z-index: 80. display: flex; - ${props => props.filter ? 'height: 80%' : ''}; - max-height: ${props => props.filter ? 'none' : '66%'}; + ${props => (props.filter ? 'height: 80%' : '')}; + max-height: ${props => (props.filter ? 'none' : '66%')}; margin: auto 0; - ${props => props.filter ? 'margin-top: 0' : ''}; + ${props => (props.filter ? 'margin-top: 0' : '')}; overflow: hidden; // Enables border radius on scrollable child elements pointer-events: auto; flex-direction: column; @@ -51,7 +51,7 @@ export const modalStyles = css` animation: ${animateModal} 0.12s cubic-bezier(0, 0.1, 0.1, 1) backwards; @media (min-width: ${get('breakpoints.0')}) { - width: ${props => props.filter ? 'auto' : '300px'}; + width: ${props => (props.filter ? 'auto' : '300px')}; height: auto; max-height: 350px; margin: ${get('space.1')}px 0 ${get('space.3')}px 0; @@ -82,15 +82,21 @@ export const wrapperStyles = css` z-index: 80; display: block; cursor: default; - content: " "; + content: ' '; background: transparent; } // Remove marker added by the display: list-item browser default - > summary { list-style: none; } + > summary { + list-style: none; + } // Remove marker added by details polyfill - > summary::before { display: none; } + > summary::before { + display: none; + } // Remove marker added by Chrome - > summary::-webkit-details-marker { display: none; } + > summary::-webkit-details-marker { + display: none; + } ` export const listStyles = css` @@ -120,12 +126,12 @@ export const listStyles = css` background-color: ${get('colors.blue.1')}; } - .SelectMenuTab:not([aria-checked="true"]):hover { + .SelectMenuTab:not([aria-checked='true']):hover { color: ${get('colors.gray.9')}; background-color: ${get('colors.gray.2')}; } - .SelectMenuTab:not([aria-checked="true"]):active { + .SelectMenuTab:not([aria-checked='true']):active { color: ${get('colors.gray.9')}; background-color: ${get('colors.gray.1')}; } @@ -156,7 +162,7 @@ export const tabStyles = css` padding: ${get('space.2')}px ${get('space.3')}px; font-size: ${get('fontSizes.0')}px; font-weight: 500; - color: ${get('colors.gray.5')}; + color: ${get('colors.gray.5')}; text-align: center; background-color: transparent; border: 0; @@ -175,7 +181,7 @@ export const tabStyles = css` border-top-right-radius: ${get('radii.1')}px; } - &[aria-selected="true"] { + &[aria-selected='true'] { z-index: 1; // Keeps box-shadow visible when hovering color: ${get('colors.gray.9')}; background-color: ${get('colors.white')}; @@ -231,7 +237,7 @@ export const listItemStyles = css` } &:focus { - outline:none; + outline: none; } .SelectMenu-selected { @@ -241,14 +247,13 @@ export const listItemStyles = css` transition: transform 0.12s cubic-bezier(0.5, 0.1, 1, 0.5), visibility 0s 0.12s linear; transform: scale(0); } - @media (min-width: ${get('breakpoints.0')}) { padding-top: ${get('space.2')}px; padding-bottom: ${get('space.2')}px; } - &[aria-checked="true"] { + &[aria-checked='true'] { font-weight: 500; color: ${get('colors.gray.9')}; @@ -289,4 +294,4 @@ export const dividerStyles = css` &:last-child { border-bottom: 0; } -` \ No newline at end of file +` diff --git a/src/SelectMenuSummary.js b/src/SelectMenuSummary.js index 3e3f936687b..b3b8899ff01 100644 --- a/src/SelectMenuSummary.js +++ b/src/SelectMenuSummary.js @@ -1,4 +1,10 @@ import React from 'react' import Button from './Button' -export default ({children, ...rest}) => +const SelectMenuSummary = ({children, ...rest}) => ( + +) + +export default SelectMenuSummary diff --git a/src/SelectMenuTab.js b/src/SelectMenuTab.js index 8b4f5ad6e7b..e394ef76110 100644 --- a/src/SelectMenuTab.js +++ b/src/SelectMenuTab.js @@ -7,7 +7,7 @@ import {COMMON} from './constants' const SelectMenuTab = styled.button.attrs(props => ({ className: 'SelectMenuTab', role: 'tab', - "aria-selected": props.selected + 'aria-selected': props.selected }))` ${tabStyles} ${COMMON} @@ -19,7 +19,7 @@ SelectMenuTab.defaultProps = { } SelectMenuTab.propTypes = { - selected: PropTypes.bool, + selected: PropTypes.bool } -export default SelectMenuTab \ No newline at end of file +export default SelectMenuTab diff --git a/src/SelectMenuTabs.js b/src/SelectMenuTabs.js index 7995da895f2..77d6b3ebd37 100644 --- a/src/SelectMenuTabs.js +++ b/src/SelectMenuTabs.js @@ -14,4 +14,4 @@ SelectMenuTabs.defaultProps = { theme } -export default SelectMenuTabs \ No newline at end of file +export default SelectMenuTabs diff --git a/src/SelectMenuTitle.js b/src/SelectMenuTitle.js index ac9ebd766fc..0942e8a8815 100644 --- a/src/SelectMenuTitle.js +++ b/src/SelectMenuTitle.js @@ -19,4 +19,4 @@ SelectMenuTitle.defaultProps = { theme } -export default SelectMenuTitle \ No newline at end of file +export default SelectMenuTitle diff --git a/src/TextInput.js b/src/TextInput.js index a0c1a9a5151..27a07ec9688 100644 --- a/src/TextInput.js +++ b/src/TextInput.js @@ -69,4 +69,4 @@ TextInput.propTypes = { width: systemPropTypes.layout.width } -export default TextInput \ No newline at end of file +export default TextInput diff --git a/src/__tests__/__snapshots__/FilterListItem.js.snap b/src/__tests__/__snapshots__/FilterListItem.js.snap index e54fe1a8095..698ca60a4f1 100644 --- a/src/__tests__/__snapshots__/FilterListItem.js.snap +++ b/src/__tests__/__snapshots__/FilterListItem.js.snap @@ -67,6 +67,10 @@ exports[`FilterList.Item renders the given "as" prop 1`] = ` "#05264c", ], "bodytext": "#24292e", + "borders": Object { + "gray": "#e1e4e8", + "grayDark": "#d1d5da", + }, "button": Object { "activeBg": "rgb(233, 236, 239)", "bg2": "rgb(239, 243, 246)", diff --git a/src/__tests__/__snapshots__/TextInput.js.snap b/src/__tests__/__snapshots__/TextInput.js.snap index 05926a9db63..6b3a99a2ccf 100644 --- a/src/__tests__/__snapshots__/TextInput.js.snap +++ b/src/__tests__/__snapshots__/TextInput.js.snap @@ -23,32 +23,14 @@ exports[`TextInput renders 1`] = ` box-shadow: rgba(27,31,35,0.075) 0px 1px 2px inset,rgba(3,102,214,0.3) 0px 0px 0px 0.2em; } -.c0.input-sm { - min-height: 28px; - padding-top: 3px; - padding-bottom: 3px; - font-size: $font-size-small; - line-height: 20px; -} - -.c0.input-lg { - padding: $spacer-1 10px; - font-size: $h4-size; -} - -.c0.input-block { - display: block; - width: 100%; -} - -@media (max-width:768px) { +@media (min-width:544px) { .c0 { font-size: 14px; } } @@ -69,6 +51,8 @@ exports[`TextInput renders block 1`] = ` border-radius: 3px; outline: none; box-shadow: rgba(27,31,35,0.075) 0px 1px 2px inset; + display: block; + width: 100%; } .c0:focus { @@ -77,32 +61,14 @@ exports[`TextInput renders block 1`] = ` box-shadow: rgba(27,31,35,0.075) 0px 1px 2px inset,rgba(3,102,214,0.3) 0px 0px 0px 0.2em; } -.c0.input-sm { - min-height: 28px; - padding-top: 3px; - padding-bottom: 3px; - font-size: $font-size-small; - line-height: 20px; -} - -.c0.input-lg { - padding: $spacer-1 10px; - font-size: $h4-size; -} - -.c0.input-block { - display: block; - width: 100%; -} - -@media (max-width:768px) { +@media (min-width:544px) { .c0 { font-size: 14px; } } @@ -125,6 +91,8 @@ exports[`TextInput renders large 1`] = ` box-shadow: rgba(27,31,35,0.075) 0px 1px 2px inset; width: large; height: large; + width: large; + height: large; } .c0:focus { @@ -133,33 +101,16 @@ exports[`TextInput renders large 1`] = ` box-shadow: rgba(27,31,35,0.075) 0px 1px 2px inset,rgba(3,102,214,0.3) 0px 0px 0px 0.2em; } -.c0.input-sm { - min-height: 28px; - padding-top: 3px; - padding-bottom: 3px; - font-size: $font-size-small; - line-height: 20px; -} - -.c0.input-lg { - padding: $spacer-1 10px; - font-size: $h4-size; -} - -.c0.input-block { - display: block; - width: 100%; -} - -@media (max-width:768px) { +@media (min-width:544px) { .c0 { font-size: 14px; } } `; @@ -181,6 +132,8 @@ exports[`TextInput renders small 1`] = ` box-shadow: rgba(27,31,35,0.075) 0px 1px 2px inset; width: small; height: small; + width: small; + height: small; } .c0:focus { @@ -189,33 +142,16 @@ exports[`TextInput renders small 1`] = ` box-shadow: rgba(27,31,35,0.075) 0px 1px 2px inset,rgba(3,102,214,0.3) 0px 0px 0px 0.2em; } -.c0.input-sm { - min-height: 28px; - padding-top: 3px; - padding-bottom: 3px; - font-size: $font-size-small; - line-height: 20px; -} - -.c0.input-lg { - padding: $spacer-1 10px; - font-size: $h4-size; -} - -.c0.input-block { - display: block; - width: 100%; -} - -@media (max-width:768px) { +@media (min-width:544px) { .c0 { font-size: 14px; } } `; diff --git a/src/__tests__/__snapshots__/UnderlineNavLink.js.snap b/src/__tests__/__snapshots__/UnderlineNavLink.js.snap index bdb67dea1dd..02a61c6701f 100644 --- a/src/__tests__/__snapshots__/UnderlineNavLink.js.snap +++ b/src/__tests__/__snapshots__/UnderlineNavLink.js.snap @@ -72,6 +72,10 @@ exports[`UnderlineNav.Link renders the given "as" prop 1`] = ` "#05264c", ], "bodytext": "#24292e", + "borders": Object { + "gray": "#e1e4e8", + "grayDark": "#d1d5da", + }, "button": Object { "activeBg": "rgb(233, 236, 239)", "bg2": "rgb(239, 243, 246)", From 8fb6bcb789ac796f99dd31021b897aa094e6a219 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 16 Oct 2019 16:12:45 -0700 Subject: [PATCH 024/196] update types --- index.d.ts | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index ab30b456370..9e8699dc7f8 100644 --- a/index.d.ts +++ b/index.d.ts @@ -128,6 +128,11 @@ declare module '@primer/components' { export const ButtonDanger: React.FunctionComponent export const Button: React.FunctionComponent + export interface AnimationPulseProps + extends CommonProps, Omit, 'color'> {} + + export const AnimationPulse: React.FunctionComponent + export interface AvatarProps extends CommonProps, Omit, 'color'> { isChild?: boolean size?: number @@ -247,6 +252,35 @@ declare module '@primer/components' { export const Sticky: React.FunctionComponent export const Fixed: React.FunctionComponent + export interface SelectMenuProps extends CommonProps, Omit, 'color'> {} + export interface SelectMenuDividerProps extends CommonProps, Omit, 'color'> {} + export interface SelectMenuFilterProps extends CommonProps, Omit, 'color'> {} + export interface SelectMenuFooterProps extends CommonProps, Omit, 'color'> {} + export interface SelectMenuHeaderProps extends CommonProps, Omit, 'color'> {} + export interface SelectMenuItemProps extends CommonProps, Omit, 'color'> {} + export interface SelectMenuListProps extends CommonProps, Omit, 'color'> {} + export interface SelectMenuLoadingProps extends CommonProps, Omit, 'color'> {} + export interface SelectMenuModalProps extends CommonProps, Omit, 'color'> {} + export interface SelectMenuSummaryProps extends CommonProps, Omit, 'color'> {} + export interface SelectMenuTabsProps extends CommonProps, Omit, 'color'> {} + export interface SelectMenuTabProps extends CommonProps, Omit, 'color'> { + selected?: boolean + } + + export const SelectMenu: React.FunctionComponent & { + Divider: React.FunctionComponent, + Filter: React.FunctionComponent, + Footer: React.FunctionComponent, + Header: React.FunctionComponent, + Item: React.FunctionComponent, + List: React.FunctionComponent, + Loading: React.FunctionComponent, + Modal: React.FunctionComponent, + Summary: React.FunctionComponent, + Tabs: React.FunctionComponent, + Tab: React.FunctionComponent, + } + export interface StateLabelProps extends CommonProps { small?: boolean status: 'issueOpened' | 'issueClosed' | 'pullOpened' | 'pullClosed' | 'pullMerged' @@ -330,7 +364,10 @@ declare module '@primer/components' { export const ProgressBar: React.FunctionComponent } - +declare module '@primer/components/src/AnimationPulse' { + import {AnimationPulse} from '@primer/components' + export default AnimationPulse +} declare module '@primer/components/src/Box' { import {Box} from '@primer/components' @@ -455,6 +492,12 @@ declare module '@primer/components/src/Fixed' { import {Fixed} from '@primer/components' export default Fixed } + +declare module '@primer/components/src/SelectMenu' { + import {SelectMenu} from '@primer/components' + export default SelectMenu +} + declare module '@primer/components/src/StateLabel' { import {StateLabel} from '@primer/components' export default StateLabel From 3753b452a84909106e7fa4a0fe2f76033629fe95 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 16 Oct 2019 16:12:55 -0700 Subject: [PATCH 025/196] rename Animation component --- docs/content/Animations.md | 4 ++-- src/{Animations.js => AnimationPulse.js} | 8 +++----- src/SelectMenuLoading.js | 6 +++--- src/index.js | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) rename src/{Animations.js => AnimationPulse.js} (78%) diff --git a/docs/content/Animations.md b/docs/content/Animations.md index 2446b9d8e2d..5277a0669a4 100644 --- a/docs/content/Animations.md +++ b/docs/content/Animations.md @@ -6,9 +6,9 @@ Use Animation helper components to provide animations to UI. ```jsx live - + - + ``` ## System props diff --git a/src/Animations.js b/src/AnimationPulse.js similarity index 78% rename from src/Animations.js rename to src/AnimationPulse.js index 3f51e39cc11..85f2b3e1b29 100644 --- a/src/Animations.js +++ b/src/AnimationPulse.js @@ -2,8 +2,6 @@ import styled, {keyframes} from 'styled-components' import {COMMON} from './constants' import theme from './theme' -const Animations = {} - const pulseKeyframes = keyframes` 0% { opacity: 0.3; @@ -18,7 +16,7 @@ const pulseKeyframes = keyframes` } ` -Animations.Pulse = styled.span` +AnimationPulse = styled.span` animation-name: ${pulseKeyframes}; animation-duration: 2s; animation-timing-function: linear; @@ -26,8 +24,8 @@ Animations.Pulse = styled.span` ${COMMON} ` -Animations.Pulse.defaultProps = { +AnimationPulse.defaultProps = { theme } -export default Animations +export default AnimationPulse diff --git a/src/SelectMenuLoading.js b/src/SelectMenuLoading.js index 6aa6db56b29..0bd89a30acb 100644 --- a/src/SelectMenuLoading.js +++ b/src/SelectMenuLoading.js @@ -1,14 +1,14 @@ import React from 'react' import Box from './Box' -import Animations from './Animations' +import AnimationPulse from './AnimationPulse' import StyledOcticon, {Octoface} from '@primer/octicons-react' const SelectMenuLoading = props => { return ( - + - + ) } diff --git a/src/index.js b/src/index.js index 1ed80aa3b4b..1ba0311ca75 100644 --- a/src/index.js +++ b/src/index.js @@ -10,7 +10,7 @@ export {default as Grid} from './Grid' export {Position, Absolute, Fixed, Relative, Sticky} from './Position' // Components -export {default as Animations} from './Animations' +export {default as AnimationPulse} from './AnimationPulse' export {default as Avatar} from './Avatar' export {default as AvatarPair} from './AvatarPair' export {default as AvatarStack} from './AvatarStack' From 954051cb3da9165abc375e9e4477fae368726b24 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 16 Oct 2019 16:26:17 -0700 Subject: [PATCH 026/196] typo --- src/AnimationPulse.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AnimationPulse.js b/src/AnimationPulse.js index 85f2b3e1b29..580c18521ba 100644 --- a/src/AnimationPulse.js +++ b/src/AnimationPulse.js @@ -16,7 +16,7 @@ const pulseKeyframes = keyframes` } ` -AnimationPulse = styled.span` +const AnimationPulse = styled.span` animation-name: ${pulseKeyframes}; animation-duration: 2s; animation-timing-function: linear; From a573a19dd48daec81bf980d3a020e52d3238e01e Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 16 Oct 2019 17:46:42 -0700 Subject: [PATCH 027/196] fix typings --- index.d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.d.ts b/index.d.ts index 9e8699dc7f8..a72a2b5e461 100644 --- a/index.d.ts +++ b/index.d.ts @@ -131,7 +131,7 @@ declare module '@primer/components' { export interface AnimationPulseProps extends CommonProps, Omit, 'color'> {} - export const AnimationPulse: React.FunctionComponent + export const AnimationPulse: React.FunctionComponent export interface AvatarProps extends CommonProps, Omit, 'color'> { isChild?: boolean @@ -257,13 +257,13 @@ declare module '@primer/components' { export interface SelectMenuFilterProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuFooterProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuHeaderProps extends CommonProps, Omit, 'color'> {} - export interface SelectMenuItemProps extends CommonProps, Omit, 'color'> {} + export interface SelectMenuItemProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuListProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuLoadingProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuModalProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuSummaryProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuTabsProps extends CommonProps, Omit, 'color'> {} - export interface SelectMenuTabProps extends CommonProps, Omit, 'color'> { + export interface SelectMenuTabProps extends CommonProps, Omit, 'color'> { selected?: boolean } From f4271413ea3f2875d41f166ba1217b2c5001b985 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 16 Oct 2019 17:49:56 -0700 Subject: [PATCH 028/196] Update index.d.ts --- index.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index a72a2b5e461..81e6c42774f 100644 --- a/index.d.ts +++ b/index.d.ts @@ -257,13 +257,13 @@ declare module '@primer/components' { export interface SelectMenuFilterProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuFooterProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuHeaderProps extends CommonProps, Omit, 'color'> {} - export interface SelectMenuItemProps extends CommonProps, Omit, 'color'> {} + export interface SelectMenuItemProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuListProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuLoadingProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuModalProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuSummaryProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuTabsProps extends CommonProps, Omit, 'color'> {} - export interface SelectMenuTabProps extends CommonProps, Omit, 'color'> { + export interface SelectMenuTabProps extends CommonProps, Omit, 'color'> { selected?: boolean } From 3a932c10afc3cf3a74b4535ed1380d8a5c8110a5 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 16 Oct 2019 17:54:35 -0700 Subject: [PATCH 029/196] Update index.d.ts --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 81e6c42774f..b86b06db0fe 100644 --- a/index.d.ts +++ b/index.d.ts @@ -263,7 +263,7 @@ declare module '@primer/components' { export interface SelectMenuModalProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuSummaryProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuTabsProps extends CommonProps, Omit, 'color'> {} - export interface SelectMenuTabProps extends CommonProps, Omit, 'color'> { + export interface SelectMenuTabProps extends CommonProps, Omit, 'color'> { selected?: boolean } From 3c2a91924f3d0ea75c23f5e1895cc35efbed154c Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 16 Oct 2019 18:03:17 -0700 Subject: [PATCH 030/196] add theme to SelectMenu --- src/SelectMenu.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/SelectMenu.js b/src/SelectMenu.js index a211db407ad..c726e9e3438 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -1,5 +1,6 @@ import styled from 'styled-components' import {COMMON} from './constants' +import theme from './theme' import {wrapperStyles} from './SelectMenuStyles' import SelectMenuDivider from './SelectMenuDivider' import SelectMenuFilter from './SelectMenuFilter' @@ -29,4 +30,7 @@ SelectMenu.Summary = SelectMenuSummary SelectMenu.Tabs = SelectMenuTabs SelectMenu.Tab = SelectMenuTab +SelectMenu.defaultProps = { + theme +} export default SelectMenu From c5af58b4a142b468868887abb7007b7fc35d0dd0 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 16 Oct 2019 18:54:42 -0700 Subject: [PATCH 031/196] fix Button system props --- src/Button.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Button.js b/src/Button.js index adb187b488a..65543ac571d 100644 --- a/src/Button.js +++ b/src/Button.js @@ -1,10 +1,8 @@ import PropTypes from 'prop-types' import styled from 'styled-components' -import {COMMON, get} from './constants' +import {COMMON, LAYOUT, get} from './constants' import theme from './theme' import getButtonStyles from './ButtonStyles' -import {layout} from 'styled-system' -import systemPropTypes from '@styled-system/prop-types' function fontSize({size = '14px', ...props}) { return { @@ -20,7 +18,7 @@ const Button = styled.button.attrs(props => ({ ${props => (props.theme ? getButtonStyles(props.theme) : '')}; ${fontSize}; ${COMMON}; - ${layout}; + ${LAYOUT}; ` Button.defaultProps = { @@ -35,7 +33,7 @@ Button.propTypes = { size: PropTypes.oneOf(['sm', 'large']), theme: PropTypes.object, ...COMMON.propTypes, - ...systemPropTypes.layout + ...LAYOUT.propTypes } export default Button From 4851f30611678042fc7f63f862804db4fb97a218 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 16 Oct 2019 19:33:57 -0700 Subject: [PATCH 032/196] add ButtonTableList component --- docs/content/Buttons.md | 2 ++ index.d.ts | 8 +++++++ src/ButtonTableList.js | 49 +++++++++++++++++++++++++++++++++++++++++ src/index.js | 1 + 4 files changed, 60 insertions(+) create mode 100644 src/ButtonTableList.js diff --git a/docs/content/Buttons.md b/docs/content/Buttons.md index d70f852defd..1b80b0c98d9 100644 --- a/docs/content/Buttons.md +++ b/docs/content/Buttons.md @@ -22,6 +22,8 @@ To create a button group, wrap `Button` elements in the `ButtonGroup` element. ` + +Button Table List ``` ## System props diff --git a/index.d.ts b/index.d.ts index b86b06db0fe..355657973b8 100644 --- a/index.d.ts +++ b/index.d.ts @@ -123,9 +123,12 @@ declare module '@primer/components' { size?: 'sm' | 'large' } + export interface ButtonTableList extends CommonProps, Omit, 'color'> {} + export const ButtonPrimary: React.FunctionComponent export const ButtonOutline: React.FunctionComponent export const ButtonDanger: React.FunctionComponent + export const ButtonTableList: React.FunctionComponent export const Button: React.FunctionComponent export interface AnimationPulseProps @@ -399,6 +402,11 @@ declare module '@primer/components/src/ButtonOutline' { export default ButtonOutline } +declare module '@primer/components/src/ButtonTableList' { + import {ButtonTableList} from '@primer/components' + export default ButtonTableList +} + declare module '@primer/components/src/Button' { import {Button} from '@primer/components' export default Button diff --git a/src/ButtonTableList.js b/src/ButtonTableList.js new file mode 100644 index 00000000000..c33a5444c97 --- /dev/null +++ b/src/ButtonTableList.js @@ -0,0 +1,49 @@ +import styled from 'styled-components' +import {COMMON, LAYOUT, TYPOGRAPHY, get} from './constants' +import theme from './theme' + + +const ButtonTableList = styled.summary` + display: inline-block; + padding: 0; + font-size: inherit; + color: ${get('colors.gray.6')}; + text-decoration: none; + white-space: nowrap; + cursor: pointer; + user-select: none; + background-color: transparent; + border: 0; + appearance: none; // Corrects inability to style clickable input types in iOS. + + &:hover { + text-decoration: underline; + } + + &:disabled { + &, + &:hover { + color: rgba(${get('colors.gray.6')}, 0.5); + cursor: default; + } + } + + &:after { + display: inline-block; + width: 0; + height: 0; + vertical-align: -2px; + content: ""; + border: 4px solid transparent; + border-top-color: currentcolor; + } + ${COMMON} + ${TYPOGRAPHY} + ${LAYOUT} +` + +ButtonTableList.defaultProps = { + theme +} + +export default ButtonTableList \ No newline at end of file diff --git a/src/index.js b/src/index.js index 1ba0311ca75..37e4b1718b8 100644 --- a/src/index.js +++ b/src/index.js @@ -19,6 +19,7 @@ export {default as ButtonDanger} from './ButtonDanger' export {default as ButtonGroup} from './ButtonGroup' export {default as ButtonOutline} from './ButtonOutline' export {default as ButtonPrimary} from './ButtonPrimary' +export {default as ButtonTableList} from './ButtonTableList' export {default as Button} from './Button' export {default as Caret} from './Caret' export {default as CircleBadge} from './CircleBadge' From e4072ae6727694d1a126a4427e45e5ae105ca459 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 16 Oct 2019 19:48:34 -0700 Subject: [PATCH 033/196] lint it up --- src/ButtonTableList.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ButtonTableList.js b/src/ButtonTableList.js index c33a5444c97..a02bc3bc1a5 100644 --- a/src/ButtonTableList.js +++ b/src/ButtonTableList.js @@ -2,7 +2,6 @@ import styled from 'styled-components' import {COMMON, LAYOUT, TYPOGRAPHY, get} from './constants' import theme from './theme' - const ButtonTableList = styled.summary` display: inline-block; padding: 0; @@ -46,4 +45,4 @@ ButtonTableList.defaultProps = { theme } -export default ButtonTableList \ No newline at end of file +export default ButtonTableList From edf5e35699595438211048c352676d598e4bd9c7 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Thu, 17 Oct 2019 12:14:16 -0700 Subject: [PATCH 034/196] types typo --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 355657973b8..724986390f0 100644 --- a/index.d.ts +++ b/index.d.ts @@ -123,7 +123,7 @@ declare module '@primer/components' { size?: 'sm' | 'large' } - export interface ButtonTableList extends CommonProps, Omit, 'color'> {} + export interface ButtonTableListProps extends CommonProps, Omit, 'color'> {} export const ButtonPrimary: React.FunctionComponent export const ButtonOutline: React.FunctionComponent From a588ca6f08b22f4072724d1718d6d6fd6f00c036 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Thu, 17 Oct 2019 13:45:35 -0700 Subject: [PATCH 035/196] ButtonTableList tweaks --- index.d.ts | 6 +++++- src/ButtonTableList.js | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index 724986390f0..a9cd6864336 100644 --- a/index.d.ts +++ b/index.d.ts @@ -123,7 +123,11 @@ declare module '@primer/components' { size?: 'sm' | 'large' } - export interface ButtonTableListProps extends CommonProps, Omit, 'color'> {} + export interface ButtonTableListProps + extends CommonProps, + TypographyProps, + LayoutProps, + Omit, 'color'> {} export const ButtonPrimary: React.FunctionComponent export const ButtonOutline: React.FunctionComponent diff --git a/src/ButtonTableList.js b/src/ButtonTableList.js index a02bc3bc1a5..925620b9564 100644 --- a/src/ButtonTableList.js +++ b/src/ButtonTableList.js @@ -5,7 +5,7 @@ import theme from './theme' const ButtonTableList = styled.summary` display: inline-block; padding: 0; - font-size: inherit; + font-size: ${get('fontSizes.1')}px; color: ${get('colors.gray.6')}; text-decoration: none; white-space: nowrap; @@ -29,6 +29,7 @@ const ButtonTableList = styled.summary` &:after { display: inline-block; + margin-left: ${get('space.1')}px; width: 0; height: 0; vertical-align: -2px; From 05fc7c879fb29c0b59cfe7d24a782ddca2d7af07 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Thu, 17 Oct 2019 15:00:03 -0700 Subject: [PATCH 036/196] fix up SelectMenu.Item --- index.d.ts | 2 +- src/SelectMenuFilter.js | 2 +- src/SelectMenuItem.js | 2 +- src/SelectMenuStyles.js | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/index.d.ts b/index.d.ts index a9cd6864336..ebda651f114 100644 --- a/index.d.ts +++ b/index.d.ts @@ -264,7 +264,7 @@ declare module '@primer/components' { export interface SelectMenuFilterProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuFooterProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuHeaderProps extends CommonProps, Omit, 'color'> {} - export interface SelectMenuItemProps extends CommonProps, Omit, 'color'> {} + export interface SelectMenuItemProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuListProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuLoadingProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuModalProps extends CommonProps, Omit, 'color'> {} diff --git a/src/SelectMenuFilter.js b/src/SelectMenuFilter.js index 29b51571af8..01873e8eb93 100644 --- a/src/SelectMenuFilter.js +++ b/src/SelectMenuFilter.js @@ -17,7 +17,7 @@ const StyledForm = styled.form` const SelectMenuFilter = props => { return ( - + ) diff --git a/src/SelectMenuItem.js b/src/SelectMenuItem.js index 734a8332f61..f189d09d1ed 100644 --- a/src/SelectMenuItem.js +++ b/src/SelectMenuItem.js @@ -6,7 +6,7 @@ import {COMMON} from './constants' import StyledOcticon from './StyledOcticon' import theme from './theme' -const StyledItem = styled.button.attrs(() => ({ +const StyledItem = styled.a.attrs(() => ({ role: 'menuitem', className: 'SelectMenu--list-item' }))` diff --git a/src/SelectMenuStyles.js b/src/SelectMenuStyles.js index 8aee4d153d1..fee1e10fc6c 100644 --- a/src/SelectMenuStyles.js +++ b/src/SelectMenuStyles.js @@ -215,8 +215,7 @@ export const tabWrapperStyles = css` ` export const listItemStyles = css` - display: flex; - align-items: center; + display:block; width: 100%; padding: ${get('space.3')}px; overflow: hidden; From 2b59e4239ec6b42c54becfadf2cd40f0d40eb853 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Thu, 17 Oct 2019 15:09:41 -0700 Subject: [PATCH 037/196] lint --- src/SelectMenuStyles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SelectMenuStyles.js b/src/SelectMenuStyles.js index fee1e10fc6c..efc2136f18f 100644 --- a/src/SelectMenuStyles.js +++ b/src/SelectMenuStyles.js @@ -215,7 +215,7 @@ export const tabWrapperStyles = css` ` export const listItemStyles = css` - display:block; + display: block; width: 100%; padding: ${get('space.3')}px; overflow: hidden; From 699d5914b6b48840351641e16d1ab999ff3ef041 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Thu, 17 Oct 2019 15:16:49 -0700 Subject: [PATCH 038/196] use display to show/hide selected icon --- src/SelectMenuStyles.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SelectMenuStyles.js b/src/SelectMenuStyles.js index efc2136f18f..1fc7781a573 100644 --- a/src/SelectMenuStyles.js +++ b/src/SelectMenuStyles.js @@ -242,7 +242,7 @@ export const listItemStyles = css` .SelectMenu-selected { width: ${get('space.3')}px; // fixed width to make sure following content aligns margin-right: ${get('space.2')}px; - visibility: hidden; + display: none; transition: transform 0.12s cubic-bezier(0.5, 0.1, 1, 0.5), visibility 0s 0.12s linear; transform: scale(0); } @@ -257,7 +257,7 @@ export const listItemStyles = css` color: ${get('colors.gray.9')}; .SelectMenu-selected { - visibility: visible; + display: inline-block; transition: transform 0.12s cubic-bezier(0, 0, 0.2, 1), visibility 0s linear; transform: scale(1); } From 85f2aaacd99f49462f4f6010b185bead7109ba16 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Thu, 17 Oct 2019 15:37:33 -0700 Subject: [PATCH 039/196] add selected prop --- index.d.ts | 4 +++- src/SelectMenuItem.js | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/index.d.ts b/index.d.ts index ebda651f114..b4a09eab07c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -264,7 +264,9 @@ declare module '@primer/components' { export interface SelectMenuFilterProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuFooterProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuHeaderProps extends CommonProps, Omit, 'color'> {} - export interface SelectMenuItemProps extends CommonProps, Omit, 'color'> {} + export interface SelectMenuItemProps extends CommonProps, Omit, 'color'> { + selected?: boolean + } export interface SelectMenuListProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuLoadingProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuModalProps extends CommonProps, Omit, 'color'> {} diff --git a/src/SelectMenuItem.js b/src/SelectMenuItem.js index f189d09d1ed..cec8342321e 100644 --- a/src/SelectMenuItem.js +++ b/src/SelectMenuItem.js @@ -14,17 +14,18 @@ const StyledItem = styled.a.attrs(() => ({ ${COMMON} ` -const SelectMenuItem = ({children, ...rest}) => { +const SelectMenuItem = ({children, selected, ...rest}) => { return ( - + {selected && } {children} ) } SelectMenuItem.defaultProps = { - theme + theme, + selected: false } export default SelectMenuItem From 9dc0bcbfc2f15b201312da53a9e4493c122ce240 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Thu, 17 Oct 2019 16:47:43 -0700 Subject: [PATCH 040/196] switch up details-menu ordering --- src/SelectMenuModal.js | 9 +-- src/SelectMenuStyles.js | 130 ++++++++++++++++++++-------------------- 2 files changed, 70 insertions(+), 69 deletions(-) diff --git a/src/SelectMenuModal.js b/src/SelectMenuModal.js index 23fcf21aa49..bb71e9b31f6 100644 --- a/src/SelectMenuModal.js +++ b/src/SelectMenuModal.js @@ -3,6 +3,7 @@ import styled from 'styled-components' import {COMMON} from './constants' import {modalStyles} from './SelectMenuStyles' import theme from './theme' +import '@github/details-menu-element' const ModalWrapper = styled.div` ${modalStyles} @@ -11,11 +12,11 @@ const ModalWrapper = styled.div` const SelectMenuModal = ({children, ...rest}) => { return ( - - + + {children} - - + + ) } diff --git a/src/SelectMenuStyles.js b/src/SelectMenuStyles.js index 1fc7781a573..df476fe5a2a 100644 --- a/src/SelectMenuStyles.js +++ b/src/SelectMenuStyles.js @@ -7,71 +7,6 @@ const animateModal = keyframes` transform: scale(0.9); } ` -export const modalStyles = css` - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 99; - display: flex; - padding: ${get('space.3')}px; - pointer-events: none; - flex-direction: column; - - &::before { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - pointer-events: none; - content: ''; - background-color: ${get('colors.blackfade50')}; - - @media (min-width: ${get('breakpoints.0')}) { - display: none; - } - } - - .modal { - position: relative; - z-index: 99; // Needs to be higher than .details-overlay's z-index: 80. - display: flex; - ${props => (props.filter ? 'height: 80%' : '')}; - max-height: ${props => (props.filter ? 'none' : '66%')}; - margin: auto 0; - ${props => (props.filter ? 'margin-top: 0' : '')}; - overflow: hidden; // Enables border radius on scrollable child elements - pointer-events: auto; - flex-direction: column; - background-color: ${get('colors.gray.1')}; - border-radius: 6px; - box-shadow: 0 0 18px rgba(0, 0, 0, 0.4); - animation: ${animateModal} 0.12s cubic-bezier(0, 0.1, 0.1, 1) backwards; - - @media (min-width: ${get('breakpoints.0')}) { - width: ${props => (props.filter ? 'auto' : '300px')}; - height: auto; - max-height: 350px; - margin: ${get('space.1')}px 0 ${get('space.3')}px 0; - font-size: ${get('fontSizes.0')}px; - border: ${get('borders.1')} ${get('colors.borders.grayDark')}; - border-radius: ${get('radii.1')}px; - box-shadow: 0 1px 5px ${get('colors.borders.blackfade15')} !default; - } - } - - @media (min-width: ${get('breakpoints.0')}) { - position: absolute; - top: auto; - right: auto; - bottom: auto; - left: auto; - padding: 0; - } -` - export const wrapperStyles = css` &[open] > summary::before { position: fixed; @@ -97,6 +32,71 @@ export const wrapperStyles = css` > summary::-webkit-details-marker { display: none; } + + .details-menu { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 99; + display: flex; + padding: ${get('space.3')}px; + pointer-events: none; + flex-direction: column; + + &::before { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + pointer-events: none; + content: ''; + background-color: ${get('colors.blackfade50')}; + + @media (min-width: ${get('breakpoints.0')}) { + display: none; + } + } + + @media (min-width: ${get('breakpoints.0')}) { + position: absolute; + top: auto; + right: auto; + bottom: auto; + left: auto; + padding: 0; + } + } +` + +export const modalStyles = css` + position: relative; + z-index: 99; // Needs to be higher than .details-overlay's z-index: 80. + display: flex; + ${props => (props.filter ? 'height: 80%' : '')}; + max-height: ${props => (props.filter ? 'none' : '66%')}; + margin: auto 0; + ${props => (props.filter ? 'margin-top: 0' : '')}; + overflow: hidden; // Enables border radius on scrollable child elements + pointer-events: auto; + flex-direction: column; + background-color: ${get('colors.gray.1')}; + border-radius: 6px; + box-shadow: 0 0 18px rgba(0, 0, 0, 0.4); + animation: ${animateModal} 0.12s cubic-bezier(0, 0.1, 0.1, 1) backwards; + + @media (min-width: ${get('breakpoints.0')}) { + width: ${props => (props.filter ? 'auto' : '300px')}; + height: auto; + max-height: 350px; + margin: ${get('space.1')}px 0 ${get('space.3')}px 0; + font-size: ${get('fontSizes.0')}px; + border: ${get('borders.1')} ${get('colors.borders.grayDark')}; + border-radius: ${get('radii.1')}px; + box-shadow: 0 1px 5px ${get('colors.borders.blackfade15')} !default; + } ` export const listStyles = css` From d5c5cf909dabda6d6c04fbe9bb662dd811f641bd Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Fri, 18 Oct 2019 09:34:29 -0700 Subject: [PATCH 041/196] lint --- docs/content/SelectMenu.md | 2 +- src/SelectMenuModal.js | 4 +--- src/SelectMenuStyles.js | 6 +++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index dd4f9671d8f..74bf0f10db1 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -13,7 +13,7 @@ title: SelectMenu Organization - Primer Components release tracking + Primer Components release tracking Primer Compononents roadmap More options Primer Components bugs diff --git a/src/SelectMenuModal.js b/src/SelectMenuModal.js index bb71e9b31f6..7dfe60d71ae 100644 --- a/src/SelectMenuModal.js +++ b/src/SelectMenuModal.js @@ -13,9 +13,7 @@ const ModalWrapper = styled.div` const SelectMenuModal = ({children, ...rest}) => { return ( - - {children} - + {children} ) } diff --git a/src/SelectMenuStyles.js b/src/SelectMenuStyles.js index df476fe5a2a..d1ddb3e368f 100644 --- a/src/SelectMenuStyles.js +++ b/src/SelectMenuStyles.js @@ -44,7 +44,7 @@ export const wrapperStyles = css` padding: ${get('space.3')}px; pointer-events: none; flex-direction: column; - + &::before { position: absolute; top: 0; @@ -54,12 +54,12 @@ export const wrapperStyles = css` pointer-events: none; content: ''; background-color: ${get('colors.blackfade50')}; - + @media (min-width: ${get('breakpoints.0')}) { display: none; } } - + @media (min-width: ${get('breakpoints.0')}) { position: absolute; top: auto; From 00472b5a8944c3d9c744f19453c2d9becbed9254 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Fri, 18 Oct 2019 09:38:37 -0700 Subject: [PATCH 042/196] don't import CE --- src/SelectMenuModal.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SelectMenuModal.js b/src/SelectMenuModal.js index 7dfe60d71ae..b35b581f70d 100644 --- a/src/SelectMenuModal.js +++ b/src/SelectMenuModal.js @@ -3,7 +3,6 @@ import styled from 'styled-components' import {COMMON} from './constants' import {modalStyles} from './SelectMenuStyles' import theme from './theme' -import '@github/details-menu-element' const ModalWrapper = styled.div` ${modalStyles} From 774f54c95b0e8de2626f332b4686c36f0547801f Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Fri, 18 Oct 2019 12:21:54 -0700 Subject: [PATCH 043/196] remove text decoration --- src/SelectMenuStyles.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SelectMenuStyles.js b/src/SelectMenuStyles.js index d1ddb3e368f..dcd85a81b98 100644 --- a/src/SelectMenuStyles.js +++ b/src/SelectMenuStyles.js @@ -225,6 +225,7 @@ export const listItemStyles = css` background-color: ${get('colors.white')}; border: 0; line-height: inherit; + text-decoration: none; & + & { // Add a top border only if the above element also is a list item From 3a33e97f89236962556d8f957b541dce46beb4ee Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Mon, 21 Oct 2019 16:22:43 -0700 Subject: [PATCH 044/196] add link --- docs/content/SelectMenu.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index 74bf0f10db1..03c0f3a1a1a 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -13,13 +13,13 @@ title: SelectMenu Organization - Primer Components release tracking - Primer Compononents roadmap + Primer Components release tracking + Primer Compononents roadmap More options - Primer Components bugs + Primer Components bugs Showing 3 of 3 From 4feab80a3a417d6fb463b3aa1193fb80a7f7498b Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Tue, 5 Nov 2019 16:00:57 -0800 Subject: [PATCH 045/196] fix up px --- src/ButtonTableList.js | 4 ++-- src/SelectMenuFilter.js | 4 ++-- src/SelectMenuHeader.js | 8 ++++---- src/SelectMenuTitle.js | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ButtonTableList.js b/src/ButtonTableList.js index 925620b9564..9a767522875 100644 --- a/src/ButtonTableList.js +++ b/src/ButtonTableList.js @@ -5,7 +5,7 @@ import theme from './theme' const ButtonTableList = styled.summary` display: inline-block; padding: 0; - font-size: ${get('fontSizes.1')}px; + font-size: ${get('fontSizes.1')}; color: ${get('colors.gray.6')}; text-decoration: none; white-space: nowrap; @@ -29,7 +29,7 @@ const ButtonTableList = styled.summary` &:after { display: inline-block; - margin-left: ${get('space.1')}px; + margin-left: ${get('space.1')}; width: 0; height: 0; vertical-align: -2px; diff --git a/src/SelectMenuFilter.js b/src/SelectMenuFilter.js index 01873e8eb93..b2ecf5fa596 100644 --- a/src/SelectMenuFilter.js +++ b/src/SelectMenuFilter.js @@ -5,13 +5,13 @@ import theme from './theme' import TextInput from './TextInput' const StyledForm = styled.form` - padding: ${get('space.3')}px; + padding: ${get('space.3')}; margin: 0; border-top: ${get('borders.1')} ${get('colors.borders.gray')}; ${COMMON} @media (min-width: ${get('breakpoints.0')}) { - padding: ${get('space.2')}px; + padding: ${get('space.2')}; } ` diff --git a/src/SelectMenuHeader.js b/src/SelectMenuHeader.js index 85b4192bd29..5774316a883 100644 --- a/src/SelectMenuHeader.js +++ b/src/SelectMenuHeader.js @@ -5,7 +5,7 @@ import theme from './theme' const SelectMenuTitle = styled.h3` flex: auto; - font-size: ${get('fontSizes.1')}px; + font-size: ${get('fontSizes.1')}; font-weight: ${get('fontWeights.bold')}; margin: 0; @@ -21,13 +21,13 @@ SelectMenuTitle.defaultProps = { const StyledHeader = styled.header` display: flex; flex: none; // fixes header from getting squeezed in Safari iOS - padding: ${get('space.3')}px; + padding: ${get('space.3')}; ${COMMON} ${TYPOGRAPHY} @media (min-width: ${get('breakpoints.0')}) { - padding-top: ${get('space.2')}px; - padding-bottom: ${get('space.2')}px; + padding-top: ${get('space.2')}; + padding-bottom: ${get('space.2')}; } ` const SelectMenuHeader = ({children, ...rest}) => { diff --git a/src/SelectMenuTitle.js b/src/SelectMenuTitle.js index 0942e8a8815..3cb3565c367 100644 --- a/src/SelectMenuTitle.js +++ b/src/SelectMenuTitle.js @@ -4,7 +4,7 @@ import theme from './theme' const SelectMenuTitle = styled.h3` flex: auto; - font-size: ${get('fontSizes.1')}px; + font-size: ${get('fontSizes.1')}; font-weight: ${get('fontWeights.bold')}; margin: 0; ${COMMON} From 66a48ba4a08ca3319ebaaffeec41c2f9f461ecd2 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 13 Nov 2019 17:12:47 -0800 Subject: [PATCH 046/196] tab navigation --- docs/content/SelectMenu.md | 30 +++++++++++++++------------- src/SelectMenu.js | 4 +++- src/SelectMenuStyles.js | 40 +++++++++++++++++++------------------- src/SelectMenuTab.js | 25 ++++++++++++++++-------- src/SelectMenuTabPanel.js | 13 +++++++++++++ src/SelectMenuTabs.js | 21 ++++++++++++++++---- 6 files changed, 86 insertions(+), 47 deletions(-) create mode 100644 src/SelectMenuTabPanel.js diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index 03c0f3a1a1a..9ecc5a9cee4 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -1,30 +1,32 @@ --- title: SelectMenu --- +import {SelectMenu} from '@primer/components' -```jsx live Robots Filter by project - - Repository - Organization + + + + + Primer Components release tracking + Primer Compononents roadmap + More options + Primer Components bugs + + + Design Systems projects + Design Systems projects 2 + Design Systems projects 3 + - - Primer Components release tracking - Primer Compononents roadmap - More options - Primer Components bugs - - Showing 3 of 3 -``` + #### With Loading State ```jsx live diff --git a/src/SelectMenu.js b/src/SelectMenu.js index c726e9e3438..3d06e8ec2a3 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -12,7 +12,8 @@ import SelectMenuLoading from './SelectMenuLoading' import SelectMenuModal from './SelectMenuModal' import SelectMenuSummary from './SelectMenuSummary' import SelectMenuTab from './SelectMenuTab' -import SelectMenuTabs from './SelectMenuTabs' +import {SelectMenuTabs} from './SelectMenuTabs' +import SelectMenuTabPanel from './SelectMenuTabPanel' const SelectMenu = styled.details` ${wrapperStyles} @@ -29,6 +30,7 @@ SelectMenu.Modal = SelectMenuModal SelectMenu.Summary = SelectMenuSummary SelectMenu.Tabs = SelectMenuTabs SelectMenu.Tab = SelectMenuTab +SelectMenu.TabPanel = SelectMenuTabPanel SelectMenu.defaultProps = { theme diff --git a/src/SelectMenuStyles.js b/src/SelectMenuStyles.js index dcd85a81b98..1137728d535 100644 --- a/src/SelectMenuStyles.js +++ b/src/SelectMenuStyles.js @@ -41,7 +41,7 @@ export const wrapperStyles = css` left: 0; z-index: 99; display: flex; - padding: ${get('space.3')}px; + padding: ${get('space.3')}; pointer-events: none; flex-direction: column; @@ -91,10 +91,10 @@ export const modalStyles = css` width: ${props => (props.filter ? 'auto' : '300px')}; height: auto; max-height: 350px; - margin: ${get('space.1')}px 0 ${get('space.3')}px 0; - font-size: ${get('fontSizes.0')}px; + margin: ${get('space.1')} 0 ${get('space.3')} 0; + font-size: ${get('fontSizes.0')}; border: ${get('borders.1')} ${get('colors.borders.grayDark')}; - border-radius: ${get('radii.1')}px; + border-radius: ${get('radii.1')}; box-shadow: 0 1px 5px ${get('colors.borders.blackfade15')} !default; } ` @@ -159,8 +159,8 @@ export const listStyles = css` export const tabStyles = css` flex: 1; - padding: ${get('space.2')}px ${get('space.3')}px; - font-size: ${get('fontSizes.0')}px; + padding: ${get('space.2')} ${get('space.3')}; + font-size: ${get('fontSizes.0')}; font-weight: 500; color: ${get('colors.gray.5')}; text-align: center; @@ -174,11 +174,11 @@ export const tabStyles = css` @media (min-width: ${get('breakpoints.0')}) { flex: none; - padding: ${get('space.1')}px ${get('space.3')}px; + padding: ${get('space.1')} ${get('space.3')}; border: ${get('borders.1')} transparent; border-bottom-width: 0; - border-top-left-radius: ${get('radii.1')}px; - border-top-right-radius: ${get('radii.1')}px; + border-top-left-radius: ${get('radii.1')}; + border-top-right-radius: ${get('radii.1')}; } &[aria-selected='true'] { @@ -209,7 +209,7 @@ export const tabWrapperStyles = css` } @media (min-width: ${get('breakpoints.0')}) { - padding: 0 ${get('space.2')}px; + padding: 0 ${get('space.2')}; border-top: 0; } ` @@ -217,7 +217,7 @@ export const tabWrapperStyles = css` export const listItemStyles = css` display: block; width: 100%; - padding: ${get('space.3')}px; + padding: ${get('space.3')}; overflow: hidden; color: ${get('colors.gray.6')}; text-align: left; @@ -241,16 +241,16 @@ export const listItemStyles = css` } .SelectMenu-selected { - width: ${get('space.3')}px; // fixed width to make sure following content aligns - margin-right: ${get('space.2')}px; + width: ${get('space.3')}; // fixed width to make sure following content aligns + margin-right: ${get('space.2')}; display: none; transition: transform 0.12s cubic-bezier(0.5, 0.1, 1, 0.5), visibility 0s 0.12s linear; transform: scale(0); } @media (min-width: ${get('breakpoints.0')}) { - padding-top: ${get('space.2')}px; - padding-bottom: ${get('space.2')}px; + padding-top: ${get('space.2')}; + padding-bottom: ${get('space.2')}; } &[aria-checked='true'] { @@ -266,21 +266,21 @@ export const listItemStyles = css` ` export const footerStyles = css` - padding: ${get('space.2')}px ${get('space.3')}px; - font-size: ${get('fontSizes.0')}px; + padding: ${get('space.2')} ${get('space.3')}; + font-size: ${get('fontSizes.0')}; color: ${get('colors.gray.5')}; text-align: center; border-top: ${get('borders.1')} ${get('colors.borders.gray')}; @media (min-width: ${get('breakpoints.0')}) { - padding: ${get('space.1')}px ${get('space.2')}px; + padding: ${get('space.1')} ${get('space.2')}; } ` export const dividerStyles = css` - padding: ${get('space.1')}px ${get('space.3')}px; + padding: ${get('space.1')} ${get('space.3')}; margin: 0; - font-size: ${get('fontSizes.0')}px; + font-size: ${get('fontSizes.0')}; font-weight: ${get('fontWeights.bold')}; color: ${get('colors.gray.5')}; background-color: ${get('colors.gray.1')}; diff --git a/src/SelectMenuTab.js b/src/SelectMenuTab.js index e394ef76110..a53caa37f3a 100644 --- a/src/SelectMenuTab.js +++ b/src/SelectMenuTab.js @@ -1,25 +1,34 @@ +import React, {useContext} from 'react' import styled from 'styled-components' import PropTypes from 'prop-types' import {tabStyles} from './SelectMenuStyles' +import {TabContext} from './SelectMenuTabs' import theme from './theme' import {COMMON} from './constants' -const SelectMenuTab = styled.button.attrs(props => ({ - className: 'SelectMenuTab', - role: 'tab', - 'aria-selected': props.selected -}))` +const TabBase = ({name, ...rest}) => { + const tabContext = useContext(TabContext) + const handleClick = () => tabContext.setSelectedTab(name) + const isSelected = tabContext.selectedTab === name + + return ( + + ) +} + +const SelectMenuTab = styled(TabBase)` ${tabStyles} ${COMMON} ` SelectMenuTab.defaultProps = { - theme, - selected: false + theme } SelectMenuTab.propTypes = { - selected: PropTypes.bool + name: PropTypes.string } export default SelectMenuTab diff --git a/src/SelectMenuTabPanel.js b/src/SelectMenuTabPanel.js new file mode 100644 index 00000000000..a2fcc4bd3c6 --- /dev/null +++ b/src/SelectMenuTabPanel.js @@ -0,0 +1,13 @@ +import React, {useContext} from 'react' +import {TabContext} from './SelectMenuTabs' + +const SelectMenuTabPanel = ({children, tabName}) => { + const tabContext = useContext(TabContext); + return ( + + ) +} + +export default SelectMenuTabPanel \ No newline at end of file diff --git a/src/SelectMenuTabs.js b/src/SelectMenuTabs.js index 77d6b3ebd37..945e7d9ce25 100644 --- a/src/SelectMenuTabs.js +++ b/src/SelectMenuTabs.js @@ -1,11 +1,24 @@ +import React, {createContext, useState} from 'react' import styled from 'styled-components' import {tabWrapperStyles} from './SelectMenuStyles' import {COMMON} from './constants' import theme from './theme' -const SelectMenuTabs = styled.nav.attrs({ - role: 'tablist' -})` +const TabContext = createContext() + +const Tabs = ({children, initialTab}) => { + const [selectedTab, setSelectedTab] = useState(initialTab) + const tabProviderValue = { selectedTab, setSelectedTab } + return ( + + + + ) +} + +const SelectMenuTabs = styled(Tabs)` ${tabWrapperStyles} ${COMMON} ` @@ -14,4 +27,4 @@ SelectMenuTabs.defaultProps = { theme } -export default SelectMenuTabs +export {TabContext, SelectMenuTabs} From 051b944674b08f6f705810ae58d7a429050399c9 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Wed, 13 Nov 2019 17:50:50 -0800 Subject: [PATCH 047/196] initial filter work --- docs/content/SelectMenu.md | 4 ++-- src/SelectMenu.js | 4 ++-- src/SelectMenuFilter.js | 16 ++++++++++++++-- src/SelectMenuModal.js | 17 ++++++++++++----- src/SelectMenuTab.js | 8 ++++---- src/SelectMenuTabs.js | 16 +++++----------- 6 files changed, 39 insertions(+), 26 deletions(-) diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index 9ecc5a9cee4..25b1c311352 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -9,11 +9,11 @@ import {SelectMenu} from '@primer/components' Filter by project - + Primer Components release tracking - Primer Compononents roadmap + Primer Components roadmap More options Primer Components bugs diff --git a/src/SelectMenu.js b/src/SelectMenu.js index 3d06e8ec2a3..5b025ee71da 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -9,10 +9,10 @@ import SelectMenuHeader from './SelectMenuHeader' import SelectMenuItem from './SelectMenuItem' import SelectMenuList from './SelectMenuList' import SelectMenuLoading from './SelectMenuLoading' -import SelectMenuModal from './SelectMenuModal' +import {SelectMenuModal} from './SelectMenuModal' import SelectMenuSummary from './SelectMenuSummary' import SelectMenuTab from './SelectMenuTab' -import {SelectMenuTabs} from './SelectMenuTabs' +import SelectMenuTabs from './SelectMenuTabs' import SelectMenuTabPanel from './SelectMenuTabPanel' const SelectMenu = styled.details` diff --git a/src/SelectMenuFilter.js b/src/SelectMenuFilter.js index b2ecf5fa596..4a7271bb880 100644 --- a/src/SelectMenuFilter.js +++ b/src/SelectMenuFilter.js @@ -1,8 +1,9 @@ -import React from 'react' +import React, {useState, useEffect} from 'react' import styled from 'styled-components' import {COMMON, get} from './constants' import theme from './theme' import TextInput from './TextInput' +import {MenuContext} from './SelectMenuModal' const StyledForm = styled.form` padding: ${get('space.3')}; @@ -16,9 +17,20 @@ const StyledForm = styled.form` ` const SelectMenuFilter = props => { + const [searchTerm, setSearchTerm] = useState('') + const handleChange = e => { + setSearchTerm(e.target.value) + } + + React.useEffect(() => { + const results = MenuContext.results.filter(item => { + item.toLowerCase().includes(searchTerm) + }) + MenuContext.setResults(results) + }, [searchTerm]) return ( - + ) } diff --git a/src/SelectMenuModal.js b/src/SelectMenuModal.js index b35b581f70d..a6928965082 100644 --- a/src/SelectMenuModal.js +++ b/src/SelectMenuModal.js @@ -1,4 +1,4 @@ -import React from 'react' +import React, {createContext, useState} from 'react' import styled from 'styled-components' import {COMMON} from './constants' import {modalStyles} from './SelectMenuStyles' @@ -8,12 +8,19 @@ const ModalWrapper = styled.div` ${modalStyles} ${COMMON} ` +const MenuContext = createContext() const SelectMenuModal = ({children, ...rest}) => { + const [selectedTab, setSelectedTab] = useState(initialTab) + const [results, setResults] = useState('') + const menuProviderValues = { selectedTab, setSelectedTab, results, setResults } return ( - - {children} - + + + {children} + + + ) } @@ -21,4 +28,4 @@ SelectMenuModal.defaultProps = { theme } -export default SelectMenuModal +export {SelectMenuModal, MenuContext} diff --git a/src/SelectMenuTab.js b/src/SelectMenuTab.js index a53caa37f3a..bbab0541c0f 100644 --- a/src/SelectMenuTab.js +++ b/src/SelectMenuTab.js @@ -2,14 +2,14 @@ import React, {useContext} from 'react' import styled from 'styled-components' import PropTypes from 'prop-types' import {tabStyles} from './SelectMenuStyles' -import {TabContext} from './SelectMenuTabs' +import {MenuContext} from './SelectMenuModal' import theme from './theme' import {COMMON} from './constants' const TabBase = ({name, ...rest}) => { - const tabContext = useContext(TabContext) - const handleClick = () => tabContext.setSelectedTab(name) - const isSelected = tabContext.selectedTab === name + const menuContext = useContext(MenuContext) + const handleClick = () => menuContext.setSelectedTab(name) + const isSelected = menuContext.selectedTab === name return ( ) diff --git a/src/SelectMenuTabPanel.js b/src/SelectMenuTabPanel.js index e79bbecfb4e..ac953c14d41 100644 --- a/src/SelectMenuTabPanel.js +++ b/src/SelectMenuTabPanel.js @@ -3,16 +3,14 @@ import SelectMenuList from './SelectMenuList' import {MenuContext} from './SelectMenuModal' const SelectMenuTabPanel = ({tabName, items}) => { - const menuContext = useContext(MenuContext); + const menuContext = useContext(MenuContext) React.useEffect(() => { - if (menuContext.selectedTab === tabName){ + if (menuContext.selectedTab === tabName) { menuContext.setItems(items) } }, [menuContext.selectedTab]) - return ( - diff --git a/src/KeyboardHook.js b/src/KeyboardHook.js new file mode 100644 index 00000000000..795d8719f39 --- /dev/null +++ b/src/KeyboardHook.js @@ -0,0 +1,74 @@ +import {useRef, useEffect} from 'react' + +function useKeyboardNav() { + const detailsRef = useRef() + const closeDetails = (details) => { + details.removeAttribute('open') + const summary = details.querySelector('summary') + if (summary) summary.focuse() + } + const openDetails = (details) => { + details.setAttribute('open') + } + const focusItem = (details, next) => { + const options = Array.from( + details.querySelectorAll('[role^="menuitem"]:not([hidden]):not([disabled]):not([aria-disabled="true"])') + ) + const selected = document.activeElement + const index = options.indexOf(selected) + const found = next ? options[index + 1] : options[index - 1] + const def = next ? options[0] : options[options.length - 1] + return found || def + } + + const isMenuItem = (el) => { + const role = el.getAttribute('role') + return role === 'menuitem' || role === 'menuitemcheckbox' || role === 'menuitemradio' + } + const handleKeyDown = (event, details) => { + if (!(event instanceof KeyboardEvent)) return + const isOpen = details.hasAttribute('open') + const isSummaryFocused = event.target instanceof Element && event.target.tagName === 'SUMMARY' + switch (event.key) { + case 'Escape': + if (isOpen) { + closeDetails(details) + event.preventDefault() + event.stopPropagation() + } + break + case 'ArrowDown': + if (isSummaryFocused && isOpen) { + openDetails(details) + } + focusItem(details, true) + event.preventDefault() + break + case 'ArrowUp': + if (isSummaryFocused && isOpen) { + openDetails() + } + focusItem(details, false) + event.preventDefault() + break + case ' ': + case 'Enter': + const selected = document.activeElement + if (selected && isMenuItem(selected) && selected.closest('details') === details) { + event.preventDefault() + event.stopPropagation() + selected.click() + } + break + } + } + useEffect(() => { + window.addEventListener('keydown', handleKeyDown(event, detailsRef)) + return () => { + window.removeEventListener('keydown', handleKeyDown(event, detailsRef)) + } + }) + return detailsRef +} + +export default useKeyboardNav \ No newline at end of file diff --git a/src/SelectMenu.js b/src/SelectMenu.js index 786ed12092c..cb9f42efe28 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -16,12 +16,20 @@ import SelectMenuSummary from './SelectMenuSummary' import SelectMenuTab from './SelectMenuTab' import SelectMenuTabs from './SelectMenuTabs' import SelectMenuTabPanel from './SelectMenuTabPanel' +import useKeyboardNav from './KeyboardHook' -const SelectMenu = styled.details` +const SelectMenu = styled(SelectMenuBase)` ${wrapperStyles} ${COMMON} ` +const SelectMenuBase = ({children, ...rest}) => { + const detailsRef = useKeyboardNav() + return ( +
{children}
+ ) +} + SelectMenu.Fragment = props => SelectMenu.Divider = SelectMenuDivider SelectMenu.Filter = SelectMenuFilter From cd010f4c0d76e00b447e854730d62a98ba4ceb1c Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Thu, 21 Nov 2019 11:11:37 -0800 Subject: [PATCH 072/196] fix linting errors --- src/KeyboardHook.js | 57 ++++++++++++++++++++++----------------- src/SelectMenu.js | 14 +++++----- src/SelectMenuList.js | 10 ++----- src/SelectMenuTabPanel.js | 1 - 4 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/KeyboardHook.js b/src/KeyboardHook.js index 795d8719f39..c252c612c12 100644 --- a/src/KeyboardHook.js +++ b/src/KeyboardHook.js @@ -1,16 +1,17 @@ import {useRef, useEffect} from 'react' +// adapted from details-menu web component https://github.com/github/details-menu-element function useKeyboardNav() { - const detailsRef = useRef() - const closeDetails = (details) => { + const details = useRef() + const closeDetails = () => { details.removeAttribute('open') const summary = details.querySelector('summary') if (summary) summary.focuse() } - const openDetails = (details) => { + const openDetails = () => { details.setAttribute('open') } - const focusItem = (details, next) => { + const focusItem = next => { const options = Array.from( details.querySelectorAll('[role^="menuitem"]:not([hidden]):not([disabled]):not([aria-disabled="true"])') ) @@ -20,12 +21,12 @@ function useKeyboardNav() { const def = next ? options[0] : options[options.length - 1] return found || def } - - const isMenuItem = (el) => { + + const isMenuItem = el => { const role = el.getAttribute('role') return role === 'menuitem' || role === 'menuitemcheckbox' || role === 'menuitemradio' } - const handleKeyDown = (event, details) => { + const handleKeyDown = (event) => { if (!(event instanceof KeyboardEvent)) return const isOpen = details.hasAttribute('open') const isSummaryFocused = event.target instanceof Element && event.target.tagName === 'SUMMARY' @@ -38,37 +39,45 @@ function useKeyboardNav() { } break case 'ArrowDown': - if (isSummaryFocused && isOpen) { - openDetails(details) + { + if (isSummaryFocused && isOpen) { + openDetails(details) + } + const target = focusItem(true) + if (target) target.focus() + event.preventDefault() } - focusItem(details, true) - event.preventDefault() break case 'ArrowUp': - if (isSummaryFocused && isOpen) { - openDetails() + { + if (isSummaryFocused && isOpen) { + openDetails() + } + const target = focusItem(false) + if (target) target.focus() + event.preventDefault() } - focusItem(details, false) - event.preventDefault() break case ' ': case 'Enter': - const selected = document.activeElement - if (selected && isMenuItem(selected) && selected.closest('details') === details) { - event.preventDefault() - event.stopPropagation() - selected.click() + { + const selected = document.activeElement + if (selected && isMenuItem(selected) && selected.closest('details') === details) { + event.preventDefault() + event.stopPropagation() + selected.click() + } } break } } useEffect(() => { - window.addEventListener('keydown', handleKeyDown(event, detailsRef)) + window.addEventListener('keydown', handleKeyDown()) return () => { - window.removeEventListener('keydown', handleKeyDown(event, detailsRef)) + window.removeEventListener('keydown', handleKeyDown()) } }) - return detailsRef + return details } -export default useKeyboardNav \ No newline at end of file +export default useKeyboardNav diff --git a/src/SelectMenu.js b/src/SelectMenu.js index cb9f42efe28..eece3ace2f7 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -18,18 +18,20 @@ import SelectMenuTabs from './SelectMenuTabs' import SelectMenuTabPanel from './SelectMenuTabPanel' import useKeyboardNav from './KeyboardHook' -const SelectMenu = styled(SelectMenuBase)` - ${wrapperStyles} - ${COMMON} -` - const SelectMenuBase = ({children, ...rest}) => { const detailsRef = useKeyboardNav() return ( -
{children}
+
+ {children} +
) } +const SelectMenu = styled(SelectMenuBase)` + ${wrapperStyles} + ${COMMON} +` + SelectMenu.Fragment = props => SelectMenu.Divider = SelectMenuDivider SelectMenu.Filter = SelectMenuFilter diff --git a/src/SelectMenuList.js b/src/SelectMenuList.js index 1594605b95c..ad864c8e05c 100644 --- a/src/SelectMenuList.js +++ b/src/SelectMenuList.js @@ -1,18 +1,12 @@ -import React, {useContext} from 'react' +import React from 'react' import styled from 'styled-components' import {listStyles} from './SelectMenuStyles' -import SelectMenuItem from './SelectMenuItem' -import PropTypes from 'prop-types' import theme from './theme' -import {MenuContext} from './SelectMenuModal' -import uuid from 'uuid' const List = ({children, ...rest}) => { return ( ) } diff --git a/src/SelectMenuTabPanel.js b/src/SelectMenuTabPanel.js index aebac4b2c5f..cb07a279139 100644 --- a/src/SelectMenuTabPanel.js +++ b/src/SelectMenuTabPanel.js @@ -1,5 +1,4 @@ import React, {useContext} from 'react' -import SelectMenuList from './SelectMenuList' import {MenuContext} from './SelectMenuModal' const SelectMenuTabPanel = ({tabName, children}) => { From 8b1b66d2db2e42dda69a75eb05fb0e6ab5c175c7 Mon Sep 17 00:00:00 2001 From: Derrick Marcey Date: Thu, 21 Nov 2019 14:14:21 -0500 Subject: [PATCH 073/196] Expose MenuContext and track filterText in context --- index.d.ts | 56 +++++++++++++++++++++-------------------- src/SelectMenu.js | 3 ++- src/SelectMenuFilter.js | 13 ++++++++-- src/SelectMenuModal.js | 5 +++- 4 files changed, 46 insertions(+), 31 deletions(-) diff --git a/index.d.ts b/index.d.ts index 66ff742d57a..923ed846811 100644 --- a/index.d.ts +++ b/index.d.ts @@ -13,15 +13,11 @@ declare module '@primer/components' { interface CommonProps extends BaseProps, StyledSystem.ColorProps, StyledSystem.SpaceProps {} - interface LayoutProps - extends BaseProps, - StyledSystem.LayoutProps {} + interface LayoutProps extends BaseProps, StyledSystem.LayoutProps {} - interface TypographyProps - extends BaseProps, - StyledSystem.TypographyProps { - whiteSpace?: 'normal' | 'nowrap' | 'pre' | 'pre-wrap' | 'pre-line' - } + interface TypographyProps extends BaseProps, StyledSystem.TypographyProps { + whiteSpace?: 'normal' | 'nowrap' | 'pre' | 'pre-wrap' | 'pre-line' + } interface BorderProps extends BaseProps, @@ -110,8 +106,7 @@ declare module '@primer/components' { export const ButtonGroup: React.FunctionComponent export const Button: React.FunctionComponent - export interface AnimationPulseProps - extends CommonProps, Omit, 'color'> {} + export interface AnimationPulseProps extends CommonProps, Omit, 'color'> {} export const AnimationPulse: React.FunctionComponent @@ -246,17 +241,21 @@ declare module '@primer/components' { preload?: boolean } export interface SelectMenuDividerProps extends CommonProps, Omit, 'color'> {} - export interface SelectMenuFilterProps extends CommonProps, Omit, 'color'> { + export interface SelectMenuFilterProps + extends CommonProps, + Omit, 'color'> { autofocus?: boolean } export interface SelectMenuFooterProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuHeaderProps extends CommonProps, Omit, 'color'> {} - export interface SelectMenuItemProps extends CommonProps, Omit, 'color'> { + export interface SelectMenuItemProps + extends CommonProps, + Omit, 'color'> { selected?: boolean } interface SelectItems { - url: string, + url: string title: string } export interface SelectMenuListProps extends CommonProps, Omit, 'color'> {} @@ -264,26 +263,29 @@ declare module '@primer/components' { export interface SelectMenuModalProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuSummaryProps extends CommonProps, Omit, 'color'> {} export interface SelectMenuTabsProps extends CommonProps, Omit, 'color'> {} - export interface SelectMenuTabProps extends CommonProps, Omit, 'color'> { - selected?: boolean + export interface SelectMenuTabProps + extends CommonProps, + Omit, 'color'> { + selected?: boolean } export interface SelectMenuFragmentProps { src: string } export const SelectMenu: React.FunctionComponent & { - Fragment: React.FunctionComponent, - Divider: React.FunctionComponent, - Filter: React.FunctionComponent, - Footer: React.FunctionComponent, - Header: React.FunctionComponent, - Item: React.FunctionComponent, - List: React.FunctionComponent, - Loading: React.FunctionComponent, - Modal: React.FunctionComponent, - Summary: React.FunctionComponent, - Tabs: React.FunctionComponent, - Tab: React.FunctionComponent, + Context: React.Context<{filterText: string | undefined}> + Fragment: React.FunctionComponent + Divider: React.FunctionComponent + Filter: React.FunctionComponent + Footer: React.FunctionComponent + Header: React.FunctionComponent + Item: React.FunctionComponent + List: React.FunctionComponent + Loading: React.FunctionComponent + Modal: React.FunctionComponent + Summary: React.FunctionComponent + Tabs: React.FunctionComponent + Tab: React.FunctionComponent } export interface StateLabelProps extends CommonProps { diff --git a/src/SelectMenu.js b/src/SelectMenu.js index eece3ace2f7..fa708d08f5f 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -11,7 +11,7 @@ import SelectMenuHeader from './SelectMenuHeader' import SelectMenuItem from './SelectMenuItem' import SelectMenuList from './SelectMenuList' import SelectMenuLoading from './SelectMenuLoading' -import {SelectMenuModal} from './SelectMenuModal' +import {SelectMenuModal, MenuContext} from './SelectMenuModal' import SelectMenuSummary from './SelectMenuSummary' import SelectMenuTab from './SelectMenuTab' import SelectMenuTabs from './SelectMenuTabs' @@ -33,6 +33,7 @@ const SelectMenu = styled(SelectMenuBase)` ` SelectMenu.Fragment = props => +SelectMenu.Context = MenuContext SelectMenu.Divider = SelectMenuDivider SelectMenu.Filter = SelectMenuFilter SelectMenu.Footer = SelectMenuFooter diff --git a/src/SelectMenuFilter.js b/src/SelectMenuFilter.js index ebc85005807..58ec3278ad4 100644 --- a/src/SelectMenuFilter.js +++ b/src/SelectMenuFilter.js @@ -1,8 +1,9 @@ -import React from 'react' +import React, {useCallback, useState, useContext, useEffect} from 'react' import styled from 'styled-components' import {COMMON, get} from './constants' import theme from './theme' import TextInput from './TextInput' +import {MenuContext} from './SelectMenuModal' const StyledForm = styled.form` padding: ${get('space.3')}; @@ -16,9 +17,17 @@ const StyledForm = styled.form` ` const SelectMenuFilter = props => { + const {setFilterText} = useContext(MenuContext) + const [value, setValue] = useState(undefined) + const onChange = ev => { + setValue(ev.target.value) + } + useEffect(() => { + setFilterText(value) + }, [value]) return ( - + ) } diff --git a/src/SelectMenuModal.js b/src/SelectMenuModal.js index 364bfc5d768..a3e759ace6b 100644 --- a/src/SelectMenuModal.js +++ b/src/SelectMenuModal.js @@ -12,9 +12,12 @@ const MenuContext = createContext() const SelectMenuModal = ({children, initialTab, ...rest}) => { const [selectedTab, setSelectedTab] = useState(initialTab) + const [filterText, setFilterText] = useState(undefined) const menuProviderValues = { selectedTab, - setSelectedTab + setSelectedTab, + filterText, + setFilterText } return ( From 2866e50202cabffcfc2a3489cc03d900bf38e466 Mon Sep 17 00:00:00 2001 From: Derrick Marcey Date: Thu, 21 Nov 2019 14:15:42 -0500 Subject: [PATCH 074/196] Remove unused import. --- src/SelectMenuFilter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SelectMenuFilter.js b/src/SelectMenuFilter.js index 58ec3278ad4..d3347db9b66 100644 --- a/src/SelectMenuFilter.js +++ b/src/SelectMenuFilter.js @@ -1,4 +1,4 @@ -import React, {useCallback, useState, useContext, useEffect} from 'react' +import React, {useState, useContext, useEffect} from 'react' import styled from 'styled-components' import {COMMON, get} from './constants' import theme from './theme' From 767075599f4d1a761a0dfe56873547addcdd8bd8 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Thu, 21 Nov 2019 11:16:07 -0800 Subject: [PATCH 075/196] typo --- src/KeyboardHook.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/KeyboardHook.js b/src/KeyboardHook.js index c252c612c12..ecdab211d74 100644 --- a/src/KeyboardHook.js +++ b/src/KeyboardHook.js @@ -72,9 +72,9 @@ function useKeyboardNav() { } } useEffect(() => { - window.addEventListener('keydown', handleKeyDown()) + window.addEventListener('keydown', handleKeyDown) return () => { - window.removeEventListener('keydown', handleKeyDown()) + window.removeEventListener('keydown', handleKeyDown) } }) return details From d4bd9e5218d4ac114737abacf4960fbaaee93b54 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Thu, 21 Nov 2019 17:46:02 -0800 Subject: [PATCH 076/196] update hook --- docs/content/SelectMenu.md | 21 +++------------ src/KeyboardHook.js | 54 +++++++++++++++++++------------------- src/SelectMenu.js | 5 ++-- 3 files changed, 34 insertions(+), 46 deletions(-) diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md index 0745a7173b2..5c64fa41f26 100644 --- a/docs/content/SelectMenu.md +++ b/docs/content/SelectMenu.md @@ -9,29 +9,16 @@ import {SelectMenu} from '@primer/components' Filter by project - hi - hi - hi - hi + 1️⃣ + 2️⃣ + 3️⃣ + 4️⃣ Showing 3 of 3 -#### With Loading State -```jsx live - - Robots - - Filter by Author - - - Loading... - - -``` - ### SelectMenu Used as a wrapper component for select menus diff --git a/src/KeyboardHook.js b/src/KeyboardHook.js index ecdab211d74..00d43266916 100644 --- a/src/KeyboardHook.js +++ b/src/KeyboardHook.js @@ -1,34 +1,35 @@ import {useRef, useEffect} from 'react' +import ReactDOM from 'react-dom' // adapted from details-menu web component https://github.com/github/details-menu-element -function useKeyboardNav() { - const details = useRef() - const closeDetails = () => { - details.removeAttribute('open') - const summary = details.querySelector('summary') - if (summary) summary.focuse() - } - const openDetails = () => { - details.setAttribute('open') - } - const focusItem = next => { - const options = Array.from( - details.querySelectorAll('[role^="menuitem"]:not([hidden]):not([disabled]):not([aria-disabled="true"])') - ) - const selected = document.activeElement - const index = options.indexOf(selected) - const found = next ? options[index + 1] : options[index - 1] - const def = next ? options[0] : options[options.length - 1] - return found || def - } - - const isMenuItem = el => { - const role = el.getAttribute('role') - return role === 'menuitem' || role === 'menuitemcheckbox' || role === 'menuitemradio' - } +function useKeyboardNav(details, thingRef) { const handleKeyDown = (event) => { + event.Handled = true + const closeDetails = () => { + details.current.removeAttribute('open') + const summary = details.current.querySelector('summary') + if (summary) summary.focus() + } + const openDetails = () => { + details.current.setAttribute('open', '') + } + const focusItem = next => { + const options = Array.from( + details.current.querySelectorAll('[role^="menuitem"]:not([hidden]):not([disabled]):not([aria-disabled="true"])') + ) + const selected = document.activeElement + const index = options.indexOf(selected) + const found = next ? options[index + 1] : options[index - 1] + const def = next ? options[0] : options[options.length - 1] + return found || def + } + + const isMenuItem = el => { + const role = el.getAttribute('role') + return role === 'menuitem' || role === 'menuitemcheckbox' || role === 'menuitemradio' + } if (!(event instanceof KeyboardEvent)) return - const isOpen = details.hasAttribute('open') + const isOpen = details.current.hasAttribute('open') const isSummaryFocused = event.target instanceof Element && event.target.tagName === 'SUMMARY' switch (event.key) { case 'Escape': @@ -77,7 +78,6 @@ function useKeyboardNav() { window.removeEventListener('keydown', handleKeyDown) } }) - return details } export default useKeyboardNav diff --git a/src/SelectMenu.js b/src/SelectMenu.js index fa708d08f5f..382d9125f3b 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -1,4 +1,4 @@ -import React from 'react' +import React, {useRef} from 'react' import styled from 'styled-components' import {COMMON} from './constants' import PropTypes from 'prop-types' @@ -19,7 +19,8 @@ import SelectMenuTabPanel from './SelectMenuTabPanel' import useKeyboardNav from './KeyboardHook' const SelectMenuBase = ({children, ...rest}) => { - const detailsRef = useKeyboardNav() + const detailsRef = useRef(null) + useKeyboardNav(detailsRef) return (
{children} From f5382fa1a209b72de7e900b1f494854b03d1a469 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Thu, 21 Nov 2019 17:49:34 -0800 Subject: [PATCH 077/196] remove e.Handled --- src/KeyboardHook.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/KeyboardHook.js b/src/KeyboardHook.js index 00d43266916..8fd51d7a650 100644 --- a/src/KeyboardHook.js +++ b/src/KeyboardHook.js @@ -4,7 +4,6 @@ import ReactDOM from 'react-dom' // adapted from details-menu web component https://github.com/github/details-menu-element function useKeyboardNav(details, thingRef) { const handleKeyDown = (event) => { - event.Handled = true const closeDetails = () => { details.current.removeAttribute('open') const summary = details.current.querySelector('summary') From 8cbbf7812802595917022a57cc3b0a72c92d2a22 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Thu, 21 Nov 2019 18:32:44 -0800 Subject: [PATCH 078/196] refactor styles --- src/SelectMenuItem.js | 2 +- src/SelectMenuStyles.js | 150 +++++++++++++++++++++------------------- 2 files changed, 78 insertions(+), 74 deletions(-) diff --git a/src/SelectMenuItem.js b/src/SelectMenuItem.js index 566ac6e72e4..6989d2630ef 100644 --- a/src/SelectMenuItem.js +++ b/src/SelectMenuItem.js @@ -8,7 +8,7 @@ import theme from './theme' const StyledItem = styled.li.attrs(() => ({ role: 'menuitem', - className: 'SelectMenu--list-item' + tabIndex: 0 }))` ${listItemStyles} ${COMMON} diff --git a/src/SelectMenuStyles.js b/src/SelectMenuStyles.js index 4832bf5a8d6..d4b7f1fa0d9 100644 --- a/src/SelectMenuStyles.js +++ b/src/SelectMenuStyles.js @@ -111,21 +111,7 @@ export const listStyles = css` -webkit-overflow-scrolling: touch; // Adds momentum + bouncy scrolling @media (hover: hover) { - body:not(.intent-mouse) .SelectMenu--list-item:focus, - .SelectMenu--list-item:focus a, - .SelectMenu--list-item:hover, - .SelectMenu--list-item:hover a { - color: ${get('colors.white')}; - background-color: ${get('colors.blue.5')}; - } - - .SelectMenu--list-item:active, - .SelectMenu--list-item:active a { - color: ${get('colors.white')}; - background-color: ${get('colors.blue.4')}; - } - - body:not(.intent-mouse) .SelectMenuTab:focus { + .SelectMenuTab:focus { background-color: ${get('colors.blue.1')}; } @@ -139,6 +125,78 @@ export const listStyles = css` background-color: ${get('colors.gray.1')}; } } +` + +export const listItemStyles = css` + width: 100%; + padding: ${get('space.3')}; + overflow: hidden; + color: ${get('colors.gray.6')}; + text-align: left; + cursor: pointer; + background-color: ${get('colors.white')}; + border: 0; + line-height: inherit; + text-decoration: none; + + a { + text-decoration: none; + color: ${get('colors.gray.6')}; + } + + & + & { + // Add a top border only if the above element also is a list item + border-top: ${get('borders.1')} ${get('colors.gray.2')}; + } + + &:hover { + text-decoration: none; + } + + &:focus { + outline: none; + background: red; + } + + .SelectMenu-selected { + width: ${get('space.3')}; // fixed width to make sure following content aligns + margin-right: ${get('space.2')}; + display: none; + transition: transform 0.12s cubic-bezier(0.5, 0.1, 1, 0.5), visibility 0s 0.12s linear; + transform: scale(0); + } + + @media (min-width: ${get('breakpoints.0')}) { + padding-top: ${get('space.2')}; + padding-bottom: ${get('space.2')}; + } + + &[aria-checked='true'] { + font-weight: 500; + color: ${get('colors.gray.9')}; + + .SelectMenu-selected { + display: inline-block; + transition: transform 0.12s cubic-bezier(0, 0, 0.2, 1), visibility 0s linear; + transform: scale(1); + } + } + + @media (hover: hover) { + &:focus, + &:focus a, + &:hover, + &:hover a { + color: ${get('colors.white')}; + background-color: ${get('colors.blue.5')}; + } + + &:active, + &:active a { + color: ${get('colors.white')}; + background-color: ${get('colors.blue.4')}; + } + } // Can not hover states // @@ -146,16 +204,16 @@ export const listStyles = css` @media (hover: none) { // Android - .SelectMenu--list-item:focus, - .SelectMenu--list-item:active { + &:focus, + &:active { background-color: ${get('colors.gray.0')}; } // iOS Safari // :active would work if ontouchstart is added to the button // Instead this tweaks the "native" highlight color - .SelectMenu--list-item, - .SelectMenu--list-item a { + -webkit-tap-highlight-color: rgba(${get('colors.gray.3')}, 0.5); + a { -webkit-tap-highlight-color: rgba(${get('colors.gray.3')}, 0.5); } } @@ -218,60 +276,6 @@ export const tabWrapperStyles = css` } ` -export const listItemStyles = css` - width: 100%; - padding: ${get('space.3')}; - overflow: hidden; - color: ${get('colors.gray.6')}; - text-align: left; - cursor: pointer; - background-color: ${get('colors.white')}; - border: 0; - line-height: inherit; - text-decoration: none; - - a { - text-decoration: none; - color: ${get('colors.gray.6')}; - } - - & + & { - // Add a top border only if the above element also is a list item - border-top: ${get('borders.1')} ${get('colors.gray.2')}; - } - - &:hover { - text-decoration: none; - } - - &:focus { - outline: none; - } - - .SelectMenu-selected { - width: ${get('space.3')}; // fixed width to make sure following content aligns - margin-right: ${get('space.2')}; - display: none; - transition: transform 0.12s cubic-bezier(0.5, 0.1, 1, 0.5), visibility 0s 0.12s linear; - transform: scale(0); - } - - @media (min-width: ${get('breakpoints.0')}) { - padding-top: ${get('space.2')}; - padding-bottom: ${get('space.2')}; - } - - &[aria-checked='true'] { - font-weight: 500; - color: ${get('colors.gray.9')}; - - .SelectMenu-selected { - display: inline-block; - transition: transform 0.12s cubic-bezier(0, 0, 0.2, 1), visibility 0s linear; - transform: scale(1); - } - } -` export const footerStyles = css` padding: ${get('space.2')} ${get('space.3')}; From d094741b2586227beed3a229415b7e74da002a91 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Thu, 21 Nov 2019 18:34:43 -0800 Subject: [PATCH 079/196] open menu if not open yet --- src/KeyboardHook.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/KeyboardHook.js b/src/KeyboardHook.js index 8fd51d7a650..128ed699554 100644 --- a/src/KeyboardHook.js +++ b/src/KeyboardHook.js @@ -40,7 +40,7 @@ function useKeyboardNav(details, thingRef) { break case 'ArrowDown': { - if (isSummaryFocused && isOpen) { + if (isSummaryFocused && !isOpen) { openDetails(details) } const target = focusItem(true) @@ -50,7 +50,7 @@ function useKeyboardNav(details, thingRef) { break case 'ArrowUp': { - if (isSummaryFocused && isOpen) { + if (isSummaryFocused && !isOpen) { openDetails() } const target = focusItem(false) From 167ea406f108edf3371b5a4269ce716c514ce319 Mon Sep 17 00:00:00 2001 From: Derrick Marcey Date: Fri, 22 Nov 2019 15:25:37 -0500 Subject: [PATCH 080/196] add event listener to details in useKeyboardNav --- src/KeyboardHook.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/KeyboardHook.js b/src/KeyboardHook.js index 128ed699554..45a84dc00c9 100644 --- a/src/KeyboardHook.js +++ b/src/KeyboardHook.js @@ -1,9 +1,8 @@ -import {useRef, useEffect} from 'react' -import ReactDOM from 'react-dom' +import {useEffect} from 'react' // adapted from details-menu web component https://github.com/github/details-menu-element -function useKeyboardNav(details, thingRef) { - const handleKeyDown = (event) => { +function useKeyboardNav(details) { + const handleKeyDown = event => { const closeDetails = () => { details.current.removeAttribute('open') const summary = details.current.querySelector('summary') @@ -22,7 +21,7 @@ function useKeyboardNav(details, thingRef) { const def = next ? options[0] : options[options.length - 1] return found || def } - + const isMenuItem = el => { const role = el.getAttribute('role') return role === 'menuitem' || role === 'menuitemcheckbox' || role === 'menuitemradio' @@ -72,9 +71,9 @@ function useKeyboardNav(details, thingRef) { } } useEffect(() => { - window.addEventListener('keydown', handleKeyDown) + details.current.addEventListener('keydown', handleKeyDown) return () => { - window.removeEventListener('keydown', handleKeyDown) + details.current.removeEventListener('keydown', handleKeyDown) } }) } From a1ee3577a7e7d9cc8aec28a91f2db15c6913191d Mon Sep 17 00:00:00 2001 From: Derrick Marcey Date: Fri, 22 Nov 2019 15:38:39 -0500 Subject: [PATCH 081/196] Prettier lint fix. --- src/SelectMenuStyles.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SelectMenuStyles.js b/src/SelectMenuStyles.js index d4b7f1fa0d9..a98b64781b2 100644 --- a/src/SelectMenuStyles.js +++ b/src/SelectMenuStyles.js @@ -276,7 +276,6 @@ export const tabWrapperStyles = css` } ` - export const footerStyles = css` padding: ${get('space.2')} ${get('space.3')}; font-size: ${get('fontSizes.0')}; From 37293f695d477e2fdb1eee45166cf87b3ae9ea77 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Fri, 22 Nov 2019 16:31:07 -0800 Subject: [PATCH 082/196] add hooks folder, export filter hook --- src/hooks/FilterHook.js | 16 ++++++++++++++++ src/{ => hooks}/KeyboardHook.js | 0 src/index.js | 4 ++++ 3 files changed, 20 insertions(+) create mode 100644 src/hooks/FilterHook.js rename src/{ => hooks}/KeyboardHook.js (100%) diff --git a/src/hooks/FilterHook.js b/src/hooks/FilterHook.js new file mode 100644 index 00000000000..51e5e032b06 --- /dev/null +++ b/src/hooks/FilterHook.js @@ -0,0 +1,16 @@ +import {useContext, useEffect, useState} from 'react' +import {MenuContext} from '../SelectMenuModal' + +function useFilter() { + const {setFilterText} = useContext(MenuContext) + const [value, setValue] = useState(undefined) + const onChange = ev => { + setValue(ev.target.value) + } + useEffect(() => { + setFilterText(value) + }, [value]) + return [value, onChange] +} + +export default useFilter \ No newline at end of file diff --git a/src/KeyboardHook.js b/src/hooks/KeyboardHook.js similarity index 100% rename from src/KeyboardHook.js rename to src/hooks/KeyboardHook.js diff --git a/src/index.js b/src/index.js index 4a889903b38..f6c55461152 100644 --- a/src/index.js +++ b/src/index.js @@ -46,3 +46,7 @@ export {default as TextInput} from './TextInput' export {default as Text} from './Text' export {default as Tooltip} from './Tooltip' export {default as UnderlineNav} from './UnderlineNav' + + +// Hooks +export {default as useFilter} from './hooks/FilterHook' From 496f0bbf99c3014200e7cf24051f23b0d06c53cc Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Fri, 22 Nov 2019 16:31:20 -0800 Subject: [PATCH 083/196] remove details-menu --- src/SelectMenuModal.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SelectMenuModal.js b/src/SelectMenuModal.js index a3e759ace6b..cfb146421f9 100644 --- a/src/SelectMenuModal.js +++ b/src/SelectMenuModal.js @@ -22,9 +22,9 @@ const SelectMenuModal = ({children, initialTab, ...rest}) => { return ( - + ) } From 66407060bd16eed7dab2feb1bf45f5b8c15b3658 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Fri, 22 Nov 2019 16:31:29 -0800 Subject: [PATCH 084/196] new hooks folder --- src/SelectMenu.js | 2 +- src/SelectMenuFilter.js | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/SelectMenu.js b/src/SelectMenu.js index 382d9125f3b..ca4da65f3e7 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -16,7 +16,7 @@ import SelectMenuSummary from './SelectMenuSummary' import SelectMenuTab from './SelectMenuTab' import SelectMenuTabs from './SelectMenuTabs' import SelectMenuTabPanel from './SelectMenuTabPanel' -import useKeyboardNav from './KeyboardHook' +import useKeyboardNav from './hooks/KeyboardHook' const SelectMenuBase = ({children, ...rest}) => { const detailsRef = useRef(null) diff --git a/src/SelectMenuFilter.js b/src/SelectMenuFilter.js index d3347db9b66..f2ee8904c04 100644 --- a/src/SelectMenuFilter.js +++ b/src/SelectMenuFilter.js @@ -4,6 +4,7 @@ import {COMMON, get} from './constants' import theme from './theme' import TextInput from './TextInput' import {MenuContext} from './SelectMenuModal' +import useFilter from './hooks/FilterHook' const StyledForm = styled.form` padding: ${get('space.3')}; @@ -17,14 +18,7 @@ const StyledForm = styled.form` ` const SelectMenuFilter = props => { - const {setFilterText} = useContext(MenuContext) - const [value, setValue] = useState(undefined) - const onChange = ev => { - setValue(ev.target.value) - } - useEffect(() => { - setFilterText(value) - }, [value]) + const [value, onChange] = useFilter() return ( From bb4da83c1d525baaa485e4f09426a936fe920ed0 Mon Sep 17 00:00:00 2001 From: Emily Plummer Date: Fri, 22 Nov 2019 16:50:44 -0800 Subject: [PATCH 085/196] move context into top level component --- src/SelectMenu.js | 21 ++++++++++++++++----- src/SelectMenuFilter.js | 2 +- src/SelectMenuModal.js | 20 ++++---------------- src/SelectMenuTab.js | 2 +- src/SelectMenuTabPanel.js | 2 +- src/hooks/FilterHook.js | 2 +- 6 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/SelectMenu.js b/src/SelectMenu.js index ca4da65f3e7..53487887013 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -11,20 +11,31 @@ import SelectMenuHeader from './SelectMenuHeader' import SelectMenuItem from './SelectMenuItem' import SelectMenuList from './SelectMenuList' import SelectMenuLoading from './SelectMenuLoading' -import {SelectMenuModal, MenuContext} from './SelectMenuModal' +import SelectMenuModal from './SelectMenuModal' import SelectMenuSummary from './SelectMenuSummary' import SelectMenuTab from './SelectMenuTab' import SelectMenuTabs from './SelectMenuTabs' import SelectMenuTabPanel from './SelectMenuTabPanel' import useKeyboardNav from './hooks/KeyboardHook' +const MenuContext = createContext() const SelectMenuBase = ({children, ...rest}) => { const detailsRef = useRef(null) + const [selectedTab, setSelectedTab] = useState(initialTab) + const [filterText, setFilterText] = useState(undefined) + const menuProviderValues = { + selectedTab, + setSelectedTab, + filterText, + setFilterText + } useKeyboardNav(detailsRef) return ( -
- {children} -
+ +
+ {children} +
+
) } @@ -55,4 +66,4 @@ SelectMenu.defaultProps = { SelectMenu.propTypes = { preload: PropTypes.bool } -export default SelectMenu +export default {SelectMenu, MenuContext} diff --git a/src/SelectMenuFilter.js b/src/SelectMenuFilter.js index f2ee8904c04..db0d3af1f80 100644 --- a/src/SelectMenuFilter.js +++ b/src/SelectMenuFilter.js @@ -3,7 +3,7 @@ import styled from 'styled-components' import {COMMON, get} from './constants' import theme from './theme' import TextInput from './TextInput' -import {MenuContext} from './SelectMenuModal' +import {MenuContext} from './SelectMenu' import useFilter from './hooks/FilterHook' const StyledForm = styled.form` diff --git a/src/SelectMenuModal.js b/src/SelectMenuModal.js index cfb146421f9..80e2717c941 100644 --- a/src/SelectMenuModal.js +++ b/src/SelectMenuModal.js @@ -8,24 +8,12 @@ const ModalWrapper = styled.div` ${modalStyles} ${COMMON} ` -const MenuContext = createContext() const SelectMenuModal = ({children, initialTab, ...rest}) => { - const [selectedTab, setSelectedTab] = useState(initialTab) - const [filterText, setFilterText] = useState(undefined) - const menuProviderValues = { - selectedTab, - setSelectedTab, - filterText, - setFilterText - } - return ( - - - + // does this need to wrap the modal wrapper? ) } @@ -33,4 +21,4 @@ SelectMenuModal.defaultProps = { theme } -export {SelectMenuModal, MenuContext} +export default SelectMenuModal diff --git a/src/SelectMenuTab.js b/src/SelectMenuTab.js index dbae38037cc..aae499ab9f2 100644 --- a/src/SelectMenuTab.js +++ b/src/SelectMenuTab.js @@ -2,7 +2,7 @@ import React, {useContext} from 'react' import styled from 'styled-components' import PropTypes from 'prop-types' import {tabStyles} from './SelectMenuStyles' -import {MenuContext} from './SelectMenuModal' +import {MenuContext} from './SelectMenu' import theme from './theme' import {COMMON} from './constants' diff --git a/src/SelectMenuTabPanel.js b/src/SelectMenuTabPanel.js index cb07a279139..a2d5a76dee2 100644 --- a/src/SelectMenuTabPanel.js +++ b/src/SelectMenuTabPanel.js @@ -1,5 +1,5 @@ import React, {useContext} from 'react' -import {MenuContext} from './SelectMenuModal' +import {MenuContext} from './SelectMenu' const SelectMenuTabPanel = ({tabName, children}) => { const menuContext = useContext(MenuContext) diff --git a/src/hooks/FilterHook.js b/src/hooks/FilterHook.js index 51e5e032b06..1818c851ae2 100644 --- a/src/hooks/FilterHook.js +++ b/src/hooks/FilterHook.js @@ -1,5 +1,5 @@ import {useContext, useEffect, useState} from 'react' -import {MenuContext} from '../SelectMenuModal' +import {MenuContext} from '../SelectMenu' function useFilter() { const {setFilterText} = useContext(MenuContext) From 5267dfb4c1cd72cd68e346ad82575f87319c08aa Mon Sep 17 00:00:00 2001 From: Derrick Marcey Date: Mon, 25 Nov 2019 08:49:29 -0500 Subject: [PATCH 086/196] Move Context into separate file to fix circular dependency --- index.d.ts | 11 ++++++++++- src/SelectMenu.js | 14 +++++++------- src/SelectMenuContext.js | 7 +++++++ src/SelectMenuFilter.js | 3 +-- src/SelectMenuModal.js | 6 +++--- src/SelectMenuTab.js | 2 +- src/SelectMenuTabPanel.js | 2 +- src/hooks/FilterHook.js | 4 ++-- src/index.js | 1 - 9 files changed, 32 insertions(+), 18 deletions(-) create mode 100644 src/SelectMenuContext.js diff --git a/index.d.ts b/index.d.ts index 923ed846811..40c9e63f77d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -273,7 +273,14 @@ declare module '@primer/components' { } export const SelectMenu: React.FunctionComponent & { - Context: React.Context<{filterText: string | undefined}> + ContextProvider: React.FunctionComponent<{ + value: { + selectedTab: string | undefined + setSelectedTab: (selectedTab: string | undefined) => void + filterText: string | undefined + setFilterText: (filterText: string | undefined) => void + } + }> Fragment: React.FunctionComponent Divider: React.FunctionComponent Filter: React.FunctionComponent @@ -386,6 +393,8 @@ declare module '@primer/components' { } export const ProgressBar: React.FunctionComponent + + export const useFilter: () => [string | undefined, (ev: React.KeyboardEvent) => void] } declare module '@primer/components/src/AnimationPulse' { diff --git a/src/SelectMenu.js b/src/SelectMenu.js index 53487887013..df9a0ebea6a 100644 --- a/src/SelectMenu.js +++ b/src/SelectMenu.js @@ -1,9 +1,10 @@ -import React, {useRef} from 'react' +import React, {useRef, useState} from 'react' import styled from 'styled-components' import {COMMON} from './constants' import PropTypes from 'prop-types' import theme from './theme' import {wrapperStyles} from './SelectMenuStyles' +import {ContextProvider} from './SelectMenuContext' import SelectMenuDivider from './SelectMenuDivider' import SelectMenuFilter from './SelectMenuFilter' import SelectMenuFooter from './SelectMenuFooter' @@ -18,8 +19,7 @@ import SelectMenuTabs from './SelectMenuTabs' import SelectMenuTabPanel from './SelectMenuTabPanel' import useKeyboardNav from './hooks/KeyboardHook' -const MenuContext = createContext() -const SelectMenuBase = ({children, ...rest}) => { +const SelectMenuBase = ({children, initialTab, ...rest}) => { const detailsRef = useRef(null) const [selectedTab, setSelectedTab] = useState(initialTab) const [filterText, setFilterText] = useState(undefined) @@ -31,11 +31,11 @@ const SelectMenuBase = ({children, ...rest}) => { } useKeyboardNav(detailsRef) return ( - +
{children}
-
+ ) } @@ -45,7 +45,7 @@ const SelectMenu = styled(SelectMenuBase)` ` SelectMenu.Fragment = props => -SelectMenu.Context = MenuContext +SelectMenu.ContextProvider = ContextProvider SelectMenu.Divider = SelectMenuDivider SelectMenu.Filter = SelectMenuFilter SelectMenu.Footer = SelectMenuFooter @@ -66,4 +66,4 @@ SelectMenu.defaultProps = { SelectMenu.propTypes = { preload: PropTypes.bool } -export default {SelectMenu, MenuContext} +export default SelectMenu diff --git a/src/SelectMenuContext.js b/src/SelectMenuContext.js new file mode 100644 index 00000000000..7314efeea56 --- /dev/null +++ b/src/SelectMenuContext.js @@ -0,0 +1,7 @@ +import React, {createContext} from 'react' + +export const MenuContext = createContext() + +export const ContextProvider = ({value, children}) => { + return {children} +} diff --git a/src/SelectMenuFilter.js b/src/SelectMenuFilter.js index db0d3af1f80..bb1dceead85 100644 --- a/src/SelectMenuFilter.js +++ b/src/SelectMenuFilter.js @@ -1,9 +1,8 @@ -import React, {useState, useContext, useEffect} from 'react' +import React from 'react' import styled from 'styled-components' import {COMMON, get} from './constants' import theme from './theme' import TextInput from './TextInput' -import {MenuContext} from './SelectMenu' import useFilter from './hooks/FilterHook' const StyledForm = styled.form` diff --git a/src/SelectMenuModal.js b/src/SelectMenuModal.js index 80e2717c941..7d2deb4b60b 100644 --- a/src/SelectMenuModal.js +++ b/src/SelectMenuModal.js @@ -1,4 +1,4 @@ -import React, {createContext, useState} from 'react' +import React from 'react' import styled from 'styled-components' import {COMMON} from './constants' import {modalStyles} from './SelectMenuStyles' @@ -9,9 +9,9 @@ const ModalWrapper = styled.div` ${COMMON} ` -const SelectMenuModal = ({children, initialTab, ...rest}) => { +const SelectMenuModal = ({children, ...rest}) => { return ( -