diff --git a/docs/content/SelectMenu.md b/docs/content/SelectMenu.md
index 69ce40bf39f..f315a4d20e5 100644
--- a/docs/content/SelectMenu.md
+++ b/docs/content/SelectMenu.md
@@ -86,12 +86,36 @@ Used to wrap the content in a `SelectMenu`.
```
+### Right-aligned modal
+
+Use the `align='right'` prop to align the modal to the right. Note that this only aligns the modal contents, and not the SelectMenu itself.
+
+```jsx live
+
+
+
+
+ Projects
+
+ Primer Components bugs
+ Primer Components roadmap
+ Project 3
+ Project 4
+
+
+
+
+```
+
### System Props
SelectMenu.Modal components get `COMMON` system props. Read our [System Props](/system-props) doc page for a full list of available props.
### Component Props
-SelectMenu.Modal components do not get any additional props besides system props.
+
+| Prop name | Type | Default | Description |
+| :-------- | :----- | :------ | ------------------------------------------------- |
+| align | String | 'left' | Use `right` to align the select menu to the right |
## SelectMenu.List
diff --git a/index.d.ts b/index.d.ts
index d26531eff7d..9a163f33134 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -287,7 +287,9 @@ declare module '@primer/components' {
initialTab?: string
}
- export interface SelectMenuModalProps extends CommonProps, Omit, 'color'> {}
+ export interface SelectMenuModalProps extends CommonProps, Omit, 'color'> {
+ align?: 'left' | 'right'
+ }
export interface SelectMenuListProps extends CommonProps, Omit, 'color'> {}
diff --git a/src/SelectMenu/SelectMenuModal.js b/src/SelectMenu/SelectMenuModal.js
index fa8f937d47c..1767e6bf9a0 100644
--- a/src/SelectMenu/SelectMenuModal.js
+++ b/src/SelectMenu/SelectMenuModal.js
@@ -1,4 +1,5 @@
import React from 'react'
+import PropTypes from 'prop-types'
import styled, {keyframes, css} from 'styled-components'
import {COMMON, get} from '../constants'
import theme from '../theme'
@@ -69,7 +70,7 @@ const modalWrapperStyles = css`
@media (min-width: ${get('breakpoints.0')}) {
position: absolute;
top: auto;
- right: auto;
+ right: ${props => (props.align === 'right' ? '0' : 'auto')};
bottom: auto;
left: auto;
padding: 0;
@@ -95,10 +96,12 @@ const SelectMenuModal = ({children, theme, ...rest}) => {
}
SelectMenuModal.defaultProps = {
+ align: 'left',
theme
}
-
SelectMenuModal.propTypes = {
+ align: PropTypes.oneOf(['left', 'right']),
+ theme: PropTypes.object,
...COMMON.propTypes,
...sx.propTypes
}
diff --git a/src/__tests__/SelectMenu.js b/src/__tests__/SelectMenu.js
index 93e5919e6f0..4699f5a5d9f 100644
--- a/src/__tests__/SelectMenu.js
+++ b/src/__tests__/SelectMenu.js
@@ -1,17 +1,17 @@
import React from 'react'
import {SelectMenu, Button} from '..'
-import {mount, renderRoot, COMPONENT_DISPLAY_NAME_REGEX, checkExports} from '../utils/testing'
+import {mount, render, renderRoot, COMPONENT_DISPLAY_NAME_REGEX, checkExports} from '../utils/testing'
import {COMMON} from '../constants'
import {render as HTMLRender, cleanup} from '@testing-library/react'
import {axe, toHaveNoViolations} from 'jest-axe'
import 'babel-polyfill'
expect.extend(toHaveNoViolations)
-const BasicSelectMenu = ({onClick, as}) => {
+const BasicSelectMenu = ({onClick, as, align = 'left'}) => {
return (
-
+
Primer Components bugs
@@ -128,4 +128,8 @@ describe('SelectMenu', () => {
item.simulate('click')
expect(component.getDOMNode().attributes.open).toBeFalsy()
})
+
+ it('right-aligned modal has right: 0px', () => {
+ expect(render()).toMatchSnapshot()
+ })
})
diff --git a/src/__tests__/__snapshots__/SelectMenu.js.snap b/src/__tests__/__snapshots__/SelectMenu.js.snap
new file mode 100644
index 00000000000..c8b29fbfa91
--- /dev/null
+++ b/src/__tests__/__snapshots__/SelectMenu.js.snap
@@ -0,0 +1,481 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`SelectMenu right-aligned modal has right: 0px 1`] = `
+.c1 {
+ position: relative;
+ display: inline-block;
+ padding: 6px 16px;
+ font-weight: 600;
+ line-height: 20px;
+ white-space: nowrap;
+ vertical-align: middle;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ border-radius: 6px;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ -webkit-text-decoration: none;
+ text-decoration: none;
+ text-align: center;
+ font-size: 14px;
+ color: #24292e;
+ background-color: #fafbfc;
+ border: 1px solid rgba(27,31,35,0.12);
+ box-shadow: 0px 1px 0px rgba(27,31,35,0.04),inset 0px 2px 0px rgba(255,255,255,0.25);
+}
+
+.c1:hover {
+ -webkit-text-decoration: none;
+ text-decoration: none;
+}
+
+.c1:focus {
+ outline: none;
+}
+
+.c1:disabled {
+ cursor: default;
+}
+
+.c1:disabled svg {
+ opacity: 0.6;
+}
+
+.c1:hover {
+ background-color: #F3F4F6;
+ box-shadow: 0px 1px 0px rgba(209,213,218,0.2),inset 0px 2px 0px rgba(255,255,255,0.1);
+}
+
+.c1:focus {
+ border-color: transparent;
+ box-shadow: 0 0 0 3px rgba(3,102,214,0.3);
+}
+
+.c1:active {
+ background-color: #edeff2;
+ box-shadow: inset 0px 2px 0px rgba(149,157,165,0.1);
+ border-color: #d1d5da;
+}
+
+.c1:disabled {
+ color: #959da5;
+ background-color: #fafbfc;
+ border-color: #eaecef;
+}
+
+.c6 {
+ padding: 4px 16px;
+ margin: 0;
+ font-size: 12px;
+ font-weight: 600;
+ color: #6a737d;
+ background-color: #f6f8fa;
+ border-bottom: 1px solid #eaecef;
+}
+
+.c7 {
+ margin-top: -1px;
+ padding: 8px 16px;
+ font-size: 12px;
+ color: #6a737d;
+ text-align: center;
+ border-top: 1px solid #e1e4e8;
+}
+
+.c5 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ padding: 16px;
+ overflow: hidden;
+ text-align: left;
+ cursor: pointer;
+ background-color: #fff;
+ border: 0;
+ border-bottom: 1px solid #eaecef;
+ color: #586069;
+ -webkit-text-decoration: none;
+ text-decoration: none;
+ font-size: 12px;
+ width: 100%;
+}
+
+.c5:hover {
+ -webkit-text-decoration: none;
+ text-decoration: none;
+}
+
+.c5:focus {
+ outline: none;
+}
+
+.c5[hidden] {
+ display: none !important;
+}
+
+.c5 .SelectMenu-icon {
+ width: 16px;
+ margin-right: 8px;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+.c5 .SelectMenu-selected-icon {
+ visibility: hidden;
+ -webkit-transition: -webkit-transform 0.12s cubic-bezier(0.5,0.1,1,0.5),visibility 0s 0.12s linear;
+ -webkit-transition: transform 0.12s cubic-bezier(0.5,0.1,1,0.5),visibility 0s 0.12s linear;
+ transition: transform 0.12s cubic-bezier(0.5,0.1,1,0.5),visibility 0s 0.12s linear;
+ -webkit-transform: scale(0);
+ -ms-transform: scale(0);
+ transform: scale(0);
+}
+
+.c5[aria-checked='true'] {
+ font-weight: 500;
+ color: #24292e;
+}
+
+.c5[aria-checked='true'] .SelectMenu-selected-icon {
+ visibility: visible;
+ -webkit-transition: -webkit-transform 0.12s cubic-bezier(0,0,0.2,1),visibility 0s linear;
+ -webkit-transition: transform 0.12s cubic-bezier(0,0,0.2,1),visibility 0s linear;
+ transition: transform 0.12s cubic-bezier(0,0,0.2,1),visibility 0s linear;
+ -webkit-transform: scale(1);
+ -ms-transform: scale(1);
+ transform: scale(1);
+}
+
+.c4 {
+ position: relative;
+ padding: 0;
+ margin: 0;
+ -webkit-flex: auto;
+ -ms-flex: auto;
+ flex: auto;
+ overflow-x: hidden;
+ overflow-y: auto;
+ background-color: #fff;
+ -webkit-overflow-scrolling: touch;
+}
+
+.c3 {
+ position: relative;
+ z-index: 99;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ max-height: 66%;
+ margin: auto 0;
+ overflow: hidden;
+ pointer-events: auto;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ background-color: #fff;
+ border-radius: 6px;
+ box-shadow: 0 1px 5px rgba(27,31,35,0.15);
+ -webkit-animation: lejQAW 0.12s cubic-bezier(0,0.1,0.1,1) backwards;
+ animation: lejQAW 0.12s cubic-bezier(0,0.1,0.1,1) backwards;
+}
+
+.c2 {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 99;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ padding: 16px;
+ pointer-events: none;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column;
+}
+
+.c2::before {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ pointer-events: none;
+ content: '';
+ background-color: rgba(27,31,35,0.5);
+}
+
+.c0[open] > summary::before {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 80;
+ display: block;
+ cursor: default;
+ content: ' ';
+ background: transparent;
+}
+
+.c0 > summary {
+ list-style: none;
+}
+
+.c0 > summary::before {
+ display: none;
+}
+
+.c0 > summary::-webkit-details-marker {
+ display: none;
+}
+
+@media (min-width:544px) {
+ .c7 {
+ padding: 4px 8px;
+ }
+}
+
+@media (min-width:544px) {
+ .c5 {
+ padding-top: 8px;
+ padding-bottom: 8px;
+ }
+}
+
+@media (hover:hover) {
+ .c5 body:not(.intent-mouse) .SelectMenu-item:focus,
+ .c5:hover,
+ .c5:active,
+ .c5:focus {
+ background-color: #f6f8fa;
+ }
+}
+
+@media (hover:none) {
+ .c5 {
+ -webkit-tap-highlight-color: rgba(#d1d5da,0.5);
+ }
+
+ .c5:focus,
+ .c5:active {
+ background-color: #fafbfc;
+ }
+}
+
+@media (hover:hover) {
+ .c4 .SelectMenuTab:focus {
+ background-color: #dbedff;
+ }
+
+ .c4 .SelectMenuTab:not([aria-checked='true']):hover {
+ color: #24292e;
+ background-color: #e1e4e8;
+ }
+
+ .c4 .SelectMenuTab:not([aria-checked='true']):active {
+ color: #24292e;
+ background-color: #f6f8fa;
+ }
+}
+
+@media (min-width:544px) {
+ .c3 {
+ width: '300px';
+ height: auto;
+ max-height: 350px;
+ margin: 4px 0 16px 0;
+ font-size: 12px;
+ border: 1px solid #d1d5da;
+ border-radius: 6px;
+ box-shadow: 0 1px 5px rgba(27,31,35,0.15) !default;
+ }
+}
+
+@media (min-width:544px) {
+ .c2::before {
+ display: none;
+ }
+}
+
+@media (min-width:544px) {
+ .c2 {
+ position: absolute;
+ top: auto;
+ right: 0;
+ bottom: auto;
+ left: auto;
+ padding: 0;
+ }
+}
+
+
+
+ Projects
+
+
+
+`;