diff --git a/.changeset/modern-icons-clean.md b/.changeset/modern-icons-clean.md new file mode 100644 index 00000000000..ac697326b5e --- /dev/null +++ b/.changeset/modern-icons-clean.md @@ -0,0 +1,5 @@ +--- +'@primer/react': minor +--- + +Migrate `Select` component to css modules diff --git a/packages/react/src/FormControl/FormControl.tsx b/packages/react/src/FormControl/FormControl.tsx index a6ccd15c858..f2eb061b594 100644 --- a/packages/react/src/FormControl/FormControl.tsx +++ b/packages/react/src/FormControl/FormControl.tsx @@ -3,7 +3,7 @@ import Autocomplete from '../Autocomplete' import Box from '../Box' import Checkbox from '../Checkbox' import Radio from '../Radio' -import Select from '../Select' +import Select from '../Select/Select' import {SelectPanel} from '../SelectPanel' import TextInput from '../TextInput' import TextInputWithTokens from '../TextInputWithTokens' diff --git a/packages/react/src/Select/Select.dev.stories.tsx b/packages/react/src/Select/Select.dev.stories.tsx new file mode 100644 index 00000000000..29faba3b0bc --- /dev/null +++ b/packages/react/src/Select/Select.dev.stories.tsx @@ -0,0 +1,25 @@ +import React from 'react' +import type {Meta} from '@storybook/react' +import {FormControl, Box} from '..' +import Select from './Select' + +export default { + title: 'Components/Select/Dev', + component: Select, +} as Meta + +export const Default = () => ( + + + Default label + + + +) diff --git a/packages/react/src/Select/Select.features.stories.tsx b/packages/react/src/Select/Select.features.stories.tsx index 1279d3d0dd6..7a1fff357bb 100644 --- a/packages/react/src/Select/Select.features.stories.tsx +++ b/packages/react/src/Select/Select.features.stories.tsx @@ -1,5 +1,6 @@ import React from 'react' -import {Select, FormControl, Box, Heading} from '..' +import {FormControl, Box, Heading} from '..' +import Select from './Select' export default { title: 'Components/Select/Features', diff --git a/packages/react/src/Select/Select.figma.tsx b/packages/react/src/Select/Select.figma.tsx index 7c75ad3f8e6..a4cbbef3fd9 100644 --- a/packages/react/src/Select/Select.figma.tsx +++ b/packages/react/src/Select/Select.figma.tsx @@ -1,5 +1,5 @@ import React from 'react' -import {Select} from '../../src' +import Select from '.' import FormControl from '../FormControl' import figma from '@figma/code-connect' diff --git a/packages/react/src/Select/Select.module.css b/packages/react/src/Select/Select.module.css new file mode 100644 index 00000000000..f3175cd0967 --- /dev/null +++ b/packages/react/src/Select/Select.module.css @@ -0,0 +1,67 @@ +.Select { + width: 100%; + /* stylelint-disable-next-line primer/spacing */ + margin-top: 1px; + /* stylelint-disable-next-line primer/spacing */ + margin-bottom: 1px; + /* stylelint-disable-next-line primer/spacing */ + margin-left: 1px; + font-size: inherit; + color: currentColor; + + /* Firefox hacks: + * 1. Makes Firefox's native dropdown menu's background match the theme. + * background-color should be 'transparent', but Firefox uses the background-color on + * so the background color doesn't hide the focus outline created with an inset box-shadow. + */ + background-color: inherit; + border: 0; + border-radius: inherit; + outline: none; + appearance: none; + + /* 2. Prevents visible overlap of partially transparent background colors. + * 'colors.input.disabledBg' happens to be partially transparent in light mode, so we use a + * transparent background-color on a disabled 's background color white when setting 'background-color: transparent;' + */ + @media screen and (forced-colors: active) { + &:disabled { + background-color: -moz-combobox; + } + } +} + +.TextInputWrapper { + position: relative; + overflow: hidden; + + @media screen and (forced-colors: active) { + svg { + fill: 'FieldText'; + } + } +} + +.disabled { + @media screen and (forced-colors: active) { + svg { + fill: 'GrayText'; + } + } +} + +.ArrowIndicator { + position: absolute; + top: 50%; + right: var(--base-size-4); + pointer-events: none; + transform: translateY(-50%); +} diff --git a/packages/react/src/Select/Select.stories.tsx b/packages/react/src/Select/Select.stories.tsx index 2cb9aeb0fb4..042f85c7d4f 100644 --- a/packages/react/src/Select/Select.stories.tsx +++ b/packages/react/src/Select/Select.stories.tsx @@ -1,7 +1,8 @@ import React from 'react' import type {Meta} from '@storybook/react' -import {Select, FormControl, Box} from '..' -import type {SelectProps} from '../Select' +import {FormControl, Box} from '..' +import Select from './Select' +import type {SelectProps} from './Select' import type {FormControlArgs} from '../utils/form-story-helpers' import { formControlArgs, diff --git a/packages/react/src/Select/Select.tsx b/packages/react/src/Select/Select.tsx index ee8eb099e22..36152a035b7 100644 --- a/packages/react/src/Select/Select.tsx +++ b/packages/react/src/Select/Select.tsx @@ -1,7 +1,11 @@ import React from 'react' import styled from 'styled-components' +import {clsx} from 'clsx' import type {StyledWrapperProps} from '../internal/components/TextInputWrapper' import TextInputWrapper from '../internal/components/TextInputWrapper' +import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent' +import {useFeatureFlag} from '../FeatureFlags' +import classes from './Select.module.css' export type SelectProps = Omit< Omit, 'size'> & Omit, @@ -10,62 +14,70 @@ export type SelectProps = Omit< placeholder?: string } -const arrowRightOffset = '4px' +const CSS_MODULES_FEATURE_FLAG = 'primer_react_css_modules_team' -const StyledSelect = styled.select` - appearance: none; - border-radius: inherit; - border: 0; - color: currentColor; - font-size: inherit; - outline: none; - width: 100%; +const arrowRightOffset = '4px' - /* Firefox hacks: */ - /* 1. Makes Firefox's native dropdown menu's background match the theme. +const StyledSelect = toggleStyledComponent( + CSS_MODULES_FEATURE_FLAG, + 'select', + styled.select` + appearance: none; + border-radius: inherit; + border: 0; + color: currentColor; + font-size: inherit; + outline: none; + width: 100%; + + /* Firefox hacks: */ + /* 1. Makes Firefox's native dropdown menu's background match the theme. background-color should be 'transparent', but Firefox uses the background-color on so the background color doesn't hide the focus outline created with an inset box-shadow. */ - background-color: inherit; - margin-top: 1px; - margin-left: 1px; - margin-bottom: 1px; + background-color: inherit; + margin-top: 1px; + margin-left: 1px; + margin-bottom: 1px; - /* 2. Prevents visible overlap of partially transparent background colors. + /* 2. Prevents visible overlap of partially transparent background colors. 'colors.input.disabledBg' happens to be partially transparent in light mode, so we use a transparent background-color on a disabled 's background color white when setting 'background-color: transparent;' */ - @media screen and (forced-colors: active) { - &:disabled { - background-color: -moz-combobox; + @media screen and (forced-colors: active) { + &:disabled { + background-color: -moz-combobox; + } } - } -` - -const ArrowIndicatorSVG: React.FC> = ({className}) => ( - + `, ) -const ArrowIndicator = styled(ArrowIndicatorSVG)` +const ArrowIndicatorSVG: React.FC> = ({className}) => { + return ( + + ) +} + +const StyledArrowIndicatorSVG = styled(ArrowIndicatorSVG)` pointer-events: none; position: absolute; right: ${arrowRightOffset}; @@ -73,43 +85,88 @@ const ArrowIndicator = styled(ArrowIndicatorSVG)` transform: translateY(-50%); ` +const ArrowIndicator: React.FC<{className?: string}> = ({className}) => { + const enabled = useFeatureFlag(CSS_MODULES_FEATURE_FLAG) + if (enabled) { + return + } + + return +} + const Select = React.forwardRef( - ({block, children, contrast, disabled, placeholder, size, required, validationStatus, ...rest}: SelectProps, ref) => ( - { + const enabled = useFeatureFlag(CSS_MODULES_FEATURE_FLAG) + if (enabled) { + return ( + + + {placeholder && ( + + )} + {children} + + + + ) + } + + return ( + - - {placeholder && ( - - )} - {children} - - - - ), + + {placeholder && ( + + )} + {children} + + + + ) + }, ) const Option: React.FC & {value: string}>> = props => ( diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index a6188c13cee..b5f7992b67c 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -137,8 +137,9 @@ export {default as RadioGroup} from './RadioGroup' export type {RelativeTimeProps} from './RelativeTime' export {default as RelativeTime} from './RelativeTime' export {SegmentedControl} from './SegmentedControl' -export {default as Select} from './Select' -export type {SelectProps} from './Select' +// Curently there is a duplicate Select component at the root of the dir, so need to be explicit about exporting from the src/Select dir +export {default as Select} from './Select/Select' +export type {SelectProps} from './Select/Select' export {SelectPanel} from './SelectPanel' export type {SelectPanelProps} from './SelectPanel' export {default as SideNav} from './SideNav'