From 43acb7fa9958dbae05832aa9e28ef7b785fa907c Mon Sep 17 00:00:00 2001 From: Cameron Dutro Date: Tue, 21 Jan 2025 11:08:58 -0800 Subject: [PATCH 01/10] Debug bulding components.json (#5579) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 586552bdbdf..dcda667caba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -415,7 +415,7 @@ jobs: run: npx tsx script/components-json/build.ts --storybook-data 'storybook-static/index.json' working-directory: packages/react - name: Build hooks.json - run: npx tsx script/hooks-json/build.ts' + run: npx tsx script/hooks-json/build.ts working-directory: packages/react sizes: From 8bdff77820a3ba9735e794f2cc0eb0e702c67bc0 Mon Sep 17 00:00:00 2001 From: Katie Langerman <18661030+langermank@users.noreply.github.com> Date: Tue, 21 Jan 2025 11:49:05 -0800 Subject: [PATCH 02/10] Hide NavList sub items if collapsed (#5567) * add display prop * Create swift-baboons-compare.md --- .changeset/swift-baboons-compare.md | 5 +++++ packages/react/src/ActionList/ActionList.module.css | 4 ++++ 2 files changed, 9 insertions(+) create mode 100644 .changeset/swift-baboons-compare.md diff --git a/.changeset/swift-baboons-compare.md b/.changeset/swift-baboons-compare.md new file mode 100644 index 00000000000..b4ff861ff05 --- /dev/null +++ b/.changeset/swift-baboons-compare.md @@ -0,0 +1,5 @@ +--- +"@primer/react": patch +--- + +Hide NavList sub items if collapsed diff --git a/packages/react/src/ActionList/ActionList.module.css b/packages/react/src/ActionList/ActionList.module.css index 9666be99f04..5abd2208d1b 100644 --- a/packages/react/src/ActionList/ActionList.module.css +++ b/packages/react/src/ActionList/ActionList.module.css @@ -466,6 +466,10 @@ transform: scaleY(1); } + & + .SubGroup { + display: none; + } + /* show active indicator on parent collapse if child is active */ &:has(+ .SubGroup [data-active='true']) { background: var(--control-transparent-bgColor-selected); From d76cd26f3accdcf06b993d3962fbea2f90f9a426 Mon Sep 17 00:00:00 2001 From: Katie Langerman <18661030+langermank@users.noreply.github.com> Date: Tue, 21 Jan 2025 14:32:01 -0800 Subject: [PATCH 03/10] Promote ActionList to staff (#5585) * staff * Create selfish-taxis-notice.md --- .changeset/selfish-taxis-notice.md | 5 +++++ packages/react/src/ActionList/featureflag.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/selfish-taxis-notice.md diff --git a/.changeset/selfish-taxis-notice.md b/.changeset/selfish-taxis-notice.md new file mode 100644 index 00000000000..e00eb97143b --- /dev/null +++ b/.changeset/selfish-taxis-notice.md @@ -0,0 +1,5 @@ +--- +"@primer/react": patch +--- + +Promote ActionList to staff diff --git a/packages/react/src/ActionList/featureflag.ts b/packages/react/src/ActionList/featureflag.ts index f4e5922f54d..77500d18538 100644 --- a/packages/react/src/ActionList/featureflag.ts +++ b/packages/react/src/ActionList/featureflag.ts @@ -1 +1 @@ -export const actionListCssModulesFlag = 'primer_react_css_modules_team' +export const actionListCssModulesFlag = 'primer_react_css_modules_staff' From 88b8533e6656f81c6351f25c2afab7f01e0acedc Mon Sep 17 00:00:00 2001 From: Hussam Ghazzi Date: Tue, 21 Jan 2025 18:12:09 -0500 Subject: [PATCH 04/10] refactor(FormControl): update FormControl to use CSS Modules behind flag (#5578) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Revert "Revert "refactor(FormControl): update FormControl to use CSS Modules …" This reverts commit 43afd36a282742e7c630e3301b35f780a834dfe9. * update InputLabel * fix css variable: --- .changeset/gentle-stingrays-search.md | 5 + package-lock.json | 8 +- .../src/FormControl/FormControl.module.css | 57 ++++++ .../react/src/FormControl/FormControl.tsx | 186 +++++++++++++----- .../FormControl/FormControlCaption.module.css | 9 + .../src/FormControl/FormControlCaption.tsx | 50 +++-- .../__tests__/FormControl.test.tsx | 54 +---- .../useFormControlForwardedProps.test.tsx | 53 +++++ .../react/src/FormControl/feature-flags.ts | 1 + .../internal/components/InputLabel.module.css | 32 +++ .../src/internal/components/InputLabel.tsx | 83 +++++--- .../components/InputValidation.module.css | 32 +++ .../internal/components/InputValidation.tsx | 37 +++- 13 files changed, 440 insertions(+), 167 deletions(-) create mode 100644 .changeset/gentle-stingrays-search.md create mode 100644 packages/react/src/FormControl/FormControl.module.css create mode 100644 packages/react/src/FormControl/FormControlCaption.module.css rename packages/react/src/{ => FormControl}/__tests__/FormControl.test.tsx (88%) create mode 100644 packages/react/src/FormControl/__tests__/useFormControlForwardedProps.test.tsx create mode 100644 packages/react/src/FormControl/feature-flags.ts create mode 100644 packages/react/src/internal/components/InputLabel.module.css create mode 100644 packages/react/src/internal/components/InputValidation.module.css diff --git a/.changeset/gentle-stingrays-search.md b/.changeset/gentle-stingrays-search.md new file mode 100644 index 00000000000..6ff383c37e5 --- /dev/null +++ b/.changeset/gentle-stingrays-search.md @@ -0,0 +1,5 @@ +--- +"@primer/react": minor +--- + +Update FormControl to use CSS Modules behind feature flag diff --git a/package-lock.json b/package-lock.json index 0e0cf32c685..92bb9d86bf7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,7 +63,7 @@ "name": "example-app-router", "version": "0.0.0", "dependencies": { - "@primer/react": "37.9.1", + "@primer/react": "37.10.0", "next": "^14.2.15", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -82,7 +82,7 @@ "react-dom": "^18.3.1" }, "devDependencies": { - "@primer/react": "37.9.1", + "@primer/react": "37.10.0", "@types/react": "^18.3.11", "@types/react-dom": "^18.3.0", "@typescript-eslint/eslint-plugin": "^7.11.0", @@ -101,7 +101,7 @@ "version": "0.0.0", "dependencies": { "@primer/octicons-react": "^19.14.0", - "@primer/react": "37.9.1", + "@primer/react": "37.10.0", "clsx": "^1.2.1", "next": "^14.2.15", "react": "^18.3.1", @@ -29864,7 +29864,7 @@ }, "packages/react": { "name": "@primer/react", - "version": "37.9.1", + "version": "37.10.0", "license": "MIT", "dependencies": { "@github/relative-time-element": "^4.4.3", diff --git a/packages/react/src/FormControl/FormControl.module.css b/packages/react/src/FormControl/FormControl.module.css new file mode 100644 index 00000000000..911f04bbde7 --- /dev/null +++ b/packages/react/src/FormControl/FormControl.module.css @@ -0,0 +1,57 @@ +.ControlHorizontalLayout { + display: flex; + + &:where([data-has-leading-visual]) { + align-items: center; + } +} + +.ControlVerticalLayout { + display: flex; + flex-direction: column; + align-items: flex-start; + + & > *:not(label) + * { + margin-top: var(--base-size-4); + } + + &[data-has-label] > * + * { + margin-top: var(--base-size-4); + } +} + +.ControlChoiceInputs > input { + margin-right: 0; + margin-left: 0; +} + +.LabelContainer { + > * { + /* stylelint-disable-next-line primer/spacing */ + padding-left: var(--stack-gap-condensed); + } + + > label { + font-weight: var(--base-text-weight-normal); + } +} + +.LeadingVisual { + margin-left: var(--base-size-8); + color: var(--fgColor-muted); + + &:where([data-disabled]) { + color: var(--control-fgColor-disabled); + } + + > * { + min-width: var(--text-body-size-large); + min-height: var(--text-body-size-large); + fill: currentColor; + } + + > *:where([data-has-caption]) { + min-width: var(--base-size-24); + min-height: var(--base-size-24); + } +} diff --git a/packages/react/src/FormControl/FormControl.tsx b/packages/react/src/FormControl/FormControl.tsx index 69d4b9bf871..8315f7be97a 100644 --- a/packages/react/src/FormControl/FormControl.tsx +++ b/packages/react/src/FormControl/FormControl.tsx @@ -1,6 +1,6 @@ +import {clsx} from 'clsx' import React, {useContext} from 'react' import Autocomplete from '../Autocomplete' -import Box from '../Box' import Checkbox from '../Checkbox' import Radio from '../Radio' import Select from '../Select/Select' @@ -10,7 +10,6 @@ import TextInputWithTokens from '../TextInputWithTokens' import Textarea from '../Textarea' import {CheckboxOrRadioGroupContext} from '../internal/components/CheckboxOrRadioGroup' import ValidationAnimationContainer from '../internal/components/ValidationAnimationContainer' -import {get} from '../constants' import {useSlots} from '../hooks/useSlots' import type {SxProp} from '../sx' import {useId} from '../hooks/useId' @@ -20,6 +19,12 @@ import FormControlLeadingVisual from './FormControlLeadingVisual' import FormControlValidation from './_FormControlValidation' import {FormControlContextProvider} from './_FormControlContext' import {warning} from '../utils/warning' +import styled from 'styled-components' +import sx from '../sx' +import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent' +import {cssModulesFlag} from './feature-flags' +import {useFeatureFlag} from '../FeatureFlags' +import classes from './FormControl.module.css' export type FormControlProps = { children?: React.ReactNode @@ -45,6 +50,7 @@ export type FormControlProps = { const FormControl = React.forwardRef( ({children, disabled: disabledProp, layout = 'vertical', id: idProp, required, sx, className}, ref) => { + const enabled = useFeatureFlag(cssModulesFlag) const [slots, childrenWithoutSlots] = useSlots(children, { caption: FormControlCaption, label: FormControlLabel, @@ -127,69 +133,62 @@ const FormControl = React.forwardRef( }} > {isChoiceInput || layout === 'horizontal' ? ( - - input': {marginLeft: 0, marginRight: 0}}}> - {React.isValidElement(InputComponent) && - React.cloneElement( - InputComponent as React.ReactElement<{ - id: string - disabled: boolean - required: boolean - ['aria-describedby']: string - }>, - { - id, - disabled, - // allow checkboxes to be required - required: required && !isRadioInput, - ['aria-describedby']: captionId as string, - }, - )} + + {React.isValidElement(InputComponent) + ? React.cloneElement( + InputComponent as React.ReactElement<{ + id: string + disabled: boolean + required: boolean + ['aria-describedby']: string + }>, + { + id, + disabled, + // allow checkboxes to be required + required: required && !isRadioInput, + ['aria-describedby']: captionId as string, + }, + ) + : null} {childrenWithoutSlots.filter( child => React.isValidElement(child) && ![Checkbox, Radio].some(inputComponent => child.type === inputComponent), )} - - {slots.leadingVisual && ( - *': { - minWidth: slots.caption ? get('fontSizes.4') : get('fontSizes.2'), - minHeight: slots.caption ? get('fontSizes.4') : get('fontSizes.2'), - fill: 'currentColor', - }, - }} - ml={2} + + {slots.leadingVisual ? ( + {slots.leadingVisual} - - )} - *': {paddingLeft: 'var(--stack-gap-condensed)'}, - '> label': {fontWeight: 'var(--base-text-weight-normal)'}, - }} - > + + ) : null} + {slots.label} {slots.caption} - - + + ) : ( - *:not(label) + *': {marginTop: 1}} : {'> * + *': {marginTop: 1}}), ...sx}} - className={className} + data-has-label={!isLabelHidden ? '' : undefined} + sx={sx} + className={clsx(className, { + [classes.ControlVerticalLayout]: enabled, + })} > {slots.label} {React.isValidElement(InputComponent) && @@ -215,13 +214,96 @@ const FormControl = React.forwardRef( {slots.validation} ) : null} {slots.caption} - + )} ) }, ) +const StyledHorizontalLayout = toggleStyledComponent( + cssModulesFlag, + 'div', + styled.div` + display: flex; + + &:where([data-has-leading-visual]) { + align-items: center; + } + + ${sx} + `, +) + +const StyledChoiceInputs = toggleStyledComponent( + cssModulesFlag, + 'div', + styled.div` + > input { + margin-left: 0; + margin-right: 0; + } + `, +) + +const StyledLabelContainer = toggleStyledComponent( + cssModulesFlag, + 'div', + styled.div` + > * { + padding-left: var(--stack-gap-condensed); + } + + > label { + font-weight: var(--base-text-weight-normal); + } + `, +) + +const StyledVerticalLayout = toggleStyledComponent( + cssModulesFlag, + 'div', + styled.div` + display: flex; + flex-direction: column; + align-items: flex-start; + + & > *:not(label) + * { + margin-top: var(--base-size-4); + } + + &:where([data-has-label]) > * + * { + margin-top: var(--base-size-4); + } + + ${sx} + `, +) + +const StyledLeadingVisual = toggleStyledComponent( + cssModulesFlag, + 'div', + styled.div` + color: var(--fgColor-default); + margin-left: var(--base-size-8); + + &:where([data-disabled]) { + color: var(--fgColor-muted); + } + + > * { + fill: currentColor; + min-width: var(--text-body-size-large); + min-height: var(--text-body-size-large); + } + + > *:where([data-has-caption]) { + min-width: var(--base-size-24); + min-height: var(--base-size-24); + } + `, +) + export default Object.assign(FormControl, { Caption: FormControlCaption, Label: FormControlLabel, diff --git a/packages/react/src/FormControl/FormControlCaption.module.css b/packages/react/src/FormControl/FormControlCaption.module.css new file mode 100644 index 00000000000..b51b54b53ca --- /dev/null +++ b/packages/react/src/FormControl/FormControlCaption.module.css @@ -0,0 +1,9 @@ +.Caption { + display: block; + font-size: var(--text-body-size-small); + color: var(--fgColor-muted); + + &:where([data-control-disabled]) { + color: var(--control-fgColor-disabled); + } +} diff --git a/packages/react/src/FormControl/FormControlCaption.tsx b/packages/react/src/FormControl/FormControlCaption.tsx index dc05e1a3bad..0b9ee2f5c64 100644 --- a/packages/react/src/FormControl/FormControlCaption.tsx +++ b/packages/react/src/FormControl/FormControlCaption.tsx @@ -1,22 +1,14 @@ +import {clsx} from 'clsx' import React from 'react' -import type {SxProp} from '../sx' -import {useFormControlContext} from './_FormControlContext' -import Text from '../Text' import styled from 'styled-components' -import {get} from '../constants' +import {cssModulesFlag} from './feature-flags' +import {useFeatureFlag} from '../FeatureFlags' +import Text from '../Text' import sx from '../sx' - -const StyledCaption = styled(Text)` - color: var(--fgColor-muted); - display: block; - font-size: ${get('fontSizes.0')}; - - &:where([data-control-disabled]) { - color: var(--control-fgColor-disabled); - } - - ${sx} -` +import type {SxProp} from '../sx' +import classes from './FormControlCaption.module.css' +import {useFormControlContext} from './_FormControlContext' +import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent' type FormControlCaptionProps = React.PropsWithChildren< { @@ -25,12 +17,36 @@ type FormControlCaptionProps = React.PropsWithChildren< > function FormControlCaption({id, children, sx}: FormControlCaptionProps) { + const enabled = useFeatureFlag(cssModulesFlag) const {captionId, disabled} = useFormControlContext() return ( - + {children} ) } +const StyledCaption = toggleStyledComponent( + cssModulesFlag, + Text, + styled(Text)` + color: var(--fgColor-muted); + display: block; + font-size: var(--text-body-size-small); + + &:where([data-control-disabled]) { + color: var(--control-fgColor-disabled); + } + + ${sx} + `, +) + export {FormControlCaption} diff --git a/packages/react/src/__tests__/FormControl.test.tsx b/packages/react/src/FormControl/__tests__/FormControl.test.tsx similarity index 88% rename from packages/react/src/__tests__/FormControl.test.tsx rename to packages/react/src/FormControl/__tests__/FormControl.test.tsx index 203f40d12c7..ba820dd28f7 100644 --- a/packages/react/src/__tests__/FormControl.test.tsx +++ b/packages/react/src/FormControl/__tests__/FormControl.test.tsx @@ -1,6 +1,5 @@ import React from 'react' import {render} from '@testing-library/react' -import {renderHook} from '@testing-library/react-hooks' import axe from 'axe-core' import { Autocomplete, @@ -12,8 +11,7 @@ import { Textarea, TextInput, TextInputWithTokens, - useFormControlForwardedProps, -} from '..' +} from '../..' import {MarkGithubIcon} from '@primer/octicons-react' const LABEL_TEXT = 'Form control' @@ -454,53 +452,3 @@ describe('FormControl', () => { }) }) }) - -describe('useFormControlForwardedProps', () => { - describe('when used outside FormControl', () => { - test('returns empty object when no props object passed', () => { - const result = renderHook(() => useFormControlForwardedProps({})) - expect(result.result.current).toEqual({}) - }) - - test('returns passed props object instance when passed', () => { - const props = {id: 'test-id'} - const result = renderHook(() => useFormControlForwardedProps(props)) - expect(result.result.current).toBe(props) - }) - }) - - test('provides context value when no props object is passed', () => { - const id = 'test-id' - - const {result} = renderHook(() => useFormControlForwardedProps({}), { - wrapper: ({children}: {children: React.ReactNode}) => ( - - Label - {children} - - ), - }) - - expect(result.current.disabled).toBe(true) - expect(result.current.id).toBe(id) - expect(result.current.required).toBe(true) - }) - - test('merges with props object, overriding to prioritize props when conflicting', () => { - const props = {id: 'override-id', xyz: 'someValue'} - - const {result} = renderHook(() => useFormControlForwardedProps(props), { - wrapper: ({children}: {children: React.ReactNode}) => ( - - Label - {children} - - ), - }) - - expect(result.current.disabled).toBe(true) - expect(result.current.id).toBe(props.id) - expect(result.current.required).toBeFalsy() - expect(result.current.xyz).toBe(props.xyz) - }) -}) diff --git a/packages/react/src/FormControl/__tests__/useFormControlForwardedProps.test.tsx b/packages/react/src/FormControl/__tests__/useFormControlForwardedProps.test.tsx new file mode 100644 index 00000000000..b71ad163989 --- /dev/null +++ b/packages/react/src/FormControl/__tests__/useFormControlForwardedProps.test.tsx @@ -0,0 +1,53 @@ +import React from 'react' +import {renderHook} from '@testing-library/react-hooks' +import FormControl, {useFormControlForwardedProps} from '../../FormControl' + +describe('useFormControlForwardedProps', () => { + describe('when used outside FormControl', () => { + test('returns empty object when no props object passed', () => { + const result = renderHook(() => useFormControlForwardedProps({})) + expect(result.result.current).toEqual({}) + }) + + test('returns passed props object instance when passed', () => { + const props = {id: 'test-id'} + const result = renderHook(() => useFormControlForwardedProps(props)) + expect(result.result.current).toBe(props) + }) + }) + + test('provides context value when no props object is passed', () => { + const id = 'test-id' + + const {result} = renderHook(() => useFormControlForwardedProps({}), { + wrapper: ({children}: {children: React.ReactNode}) => ( + + Label + {children} + + ), + }) + + expect(result.current.disabled).toBe(true) + expect(result.current.id).toBe(id) + expect(result.current.required).toBe(true) + }) + + test('merges with props object, overriding to prioritize props when conflicting', () => { + const props = {id: 'override-id', xyz: 'someValue'} + + const {result} = renderHook(() => useFormControlForwardedProps(props), { + wrapper: ({children}: {children: React.ReactNode}) => ( + + Label + {children} + + ), + }) + + expect(result.current.disabled).toBe(true) + expect(result.current.id).toBe(props.id) + expect(result.current.required).toBeFalsy() + expect(result.current.xyz).toBe(props.xyz) + }) +}) diff --git a/packages/react/src/FormControl/feature-flags.ts b/packages/react/src/FormControl/feature-flags.ts new file mode 100644 index 00000000000..0ea24433c23 --- /dev/null +++ b/packages/react/src/FormControl/feature-flags.ts @@ -0,0 +1 @@ +export const cssModulesFlag = 'primer_react_css_modules_team' diff --git a/packages/react/src/internal/components/InputLabel.module.css b/packages/react/src/internal/components/InputLabel.module.css new file mode 100644 index 00000000000..d021d9d724c --- /dev/null +++ b/packages/react/src/internal/components/InputLabel.module.css @@ -0,0 +1,32 @@ +.Label { + display: block; + font-size: var(--text-body-size-medium); + font-weight: var(--base-text-weight-semibold); + color: var(--fgColor-default); + cursor: pointer; + align-self: flex-start; + + &:where([data-control-disabled]) { + color: var(--fgColor-muted); + cursor: not-allowed; + } + + &:where([data-visually-hidden]) { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + /* stylelint-disable-next-line primer/spacing */ + margin: -1px; + overflow: hidden; + clip: rect(0 0 0 0); + white-space: nowrap; + border: 0; + clip-path: inset(50%); + } +} + +.RequiredText { + display: flex; + column-gap: var(--base-size-4); +} diff --git a/packages/react/src/internal/components/InputLabel.tsx b/packages/react/src/internal/components/InputLabel.tsx index 9126d192086..54002f3a3fb 100644 --- a/packages/react/src/internal/components/InputLabel.tsx +++ b/packages/react/src/internal/components/InputLabel.tsx @@ -1,7 +1,11 @@ +import {clsx} from 'clsx' import React from 'react' import styled from 'styled-components' -import {get} from '../../constants' import sx, {type SxProp} from '../../sx' +import {cssModulesFlag} from '../../FormControl/feature-flags' +import {useFeatureFlag} from '../../FeatureFlags' +import classes from './InputLabel.module.css' +import {toggleStyledComponent} from '../utils/toggleStyledComponent' type BaseProps = SxProp & { disabled?: boolean @@ -39,6 +43,7 @@ function InputLabel({ className, ...props }: Props) { + const enabled = useFeatureFlag(cssModulesFlag) return ( {required || requiredText ? ( - + {children} {requiredText ?? '*'} @@ -62,38 +73,46 @@ function InputLabel({ ) } -const StyledRequiredText = styled.span` - display: flex; - column-gap: ${get('space.1')}; -` +const StyledLabel = toggleStyledComponent( + cssModulesFlag, + 'label', + styled.label` + align-self: flex-start; + display: block; + color: var(--fgColor-default); + cursor: pointer; + font-weight: 600; + font-size: var(--text-body-size-medium); -const StyledLabel = styled.label` - align-self: flex-start; - display: block; - color: var(--fgColor-default); - cursor: pointer; - font-weight: 600; - font-size: ${get('fontSizes.1')}; + &:where([data-control-disabled]) { + color: var(--fgColor-muted); + cursor: not-allowed; + } - &:where([data-control-disabled]) { - color: var(--fgColor-muted); - cursor: not-allowed; - } + &:where([data-visually-hidden]) { + border: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + white-space: nowrap; + width: 1px; + } - &:where([data-visually-hidden]) { - border: 0; - clip: rect(0 0 0 0); - clip-path: inset(50%); - height: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute; - white-space: nowrap; - width: 1px; - } + ${sx} + `, +) - ${sx} -` +const StyledRequiredText = toggleStyledComponent( + cssModulesFlag, + 'span', + styled.span` + display: flex; + column-gap: var(--base-size-4); + `, +) export {InputLabel} diff --git a/packages/react/src/internal/components/InputValidation.module.css b/packages/react/src/internal/components/InputValidation.module.css new file mode 100644 index 00000000000..97428fbb395 --- /dev/null +++ b/packages/react/src/internal/components/InputValidation.module.css @@ -0,0 +1,32 @@ +.InputValidation { + display: flex; + font-size: var(--text-body-size-small); + font-weight: var(--base-text-weight-semibold); + /* stylelint-disable-next-line primer/colors */ + color: var(--inputValidation-fgColor); + + & :where(a) { + color: currentColor; + text-decoration: underline; + } + + &:where([data-validation-status='success']) { + --inputValidation-fgColor: var(--fgColor-success); + } + + &:where([data-validation-status='error']) { + --inputValidation-fgColor: var(--fgColor-danger); + } +} + +.ValidationIcon { + align-items: center; + display: flex; + margin-inline-end: var(--base-size-4); + min-height: var(--inputValidation-iconSize); +} + +.ValidationText { + /* stylelint-disable-next-line primer/typography */ + line-height: var(--inputValidation-lineHeight); +} diff --git a/packages/react/src/internal/components/InputValidation.tsx b/packages/react/src/internal/components/InputValidation.tsx index d23fe867cb5..d7224c429fa 100644 --- a/packages/react/src/internal/components/InputValidation.tsx +++ b/packages/react/src/internal/components/InputValidation.tsx @@ -1,12 +1,15 @@ import type {IconProps} from '@primer/octicons-react' import {AlertFillIcon, CheckCircleFillIcon} from '@primer/octicons-react' +import {clsx} from 'clsx' import React from 'react' +import styled from 'styled-components' import Text from '../../Text' +import sx from '../../sx' import type {SxProp} from '../../sx' +import {cssModulesFlag} from '../../FormControl/feature-flags' import type {FormValidationStatus} from '../../utils/types/FormValidationStatus' -import styled from 'styled-components' -import {get} from '../../constants' -import sx from '../../sx' +import {useFeatureFlag} from '../../FeatureFlags' +import classes from './InputValidation.module.css' type Props = { id: string @@ -22,6 +25,7 @@ const validationIconMap: Record< } const InputValidation: React.FC> = ({children, id, validationStatus, sx}) => { + const enabled = useFeatureFlag(cssModulesFlag) const IconComponent = validationStatus ? validationIconMap[validationStatus] : undefined // TODO: use `text-caption-lineHeight` token as a custom property when it's available @@ -31,10 +35,19 @@ const InputValidation: React.FC> = ({children, id const iconBoxMinHeight = iconSize * captionLineHeight return ( - + {IconComponent ? ( ) : null} - + {children} @@ -54,7 +73,7 @@ const InputValidation: React.FC> = ({children, id const StyledInputValidation = styled(Text)` color: var(--inputValidation-fgColor); display: flex; - font-size: ${get('fontSizes.0')}; + font-size: var(--text-body-size-small); font-weight: 600; & :where(a) { @@ -63,11 +82,11 @@ const StyledInputValidation = styled(Text)` } &:where([data-validation-status='success']) { - --inputValidation-fgColor: ${get('colors.success.fg')}; + --inputValidation-fgColor: var(--fgColor-success); } &:where([data-validation-status='error']) { - --inputValidation-fgColor: ${get('colors.danger.fg')}; + --inputValidation-fgColor: var(--fgColor-danger); } ${sx} @@ -76,7 +95,7 @@ const StyledInputValidation = styled(Text)` const StyledValidationIcon = styled.span` align-items: center; display: flex; - margin-inline-end: ${get('space.1')}; + margin-inline-end: var(--base-size-4); min-height: var(--inputValidation-iconSize); ` From 191950e56f0e21b008b5945c7177b72c5373736f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 19:28:59 -0500 Subject: [PATCH 05/10] chore(deps): bump @primer/behaviors from 1.7.2 to 1.8.0 (#5572) Bumps [@primer/behaviors](https://github.com/primer/behaviors) from 1.7.2 to 1.8.0. - [Release notes](https://github.com/primer/behaviors/releases) - [Changelog](https://github.com/primer/behaviors/blob/main/CHANGELOG.md) - [Commits](https://github.com/primer/behaviors/compare/v1.7.2...v1.8.0) --- updated-dependencies: - dependency-name: "@primer/behaviors" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marie Lucca <40550942+francinelucca@users.noreply.github.com> --- package-lock.json | 6 ++++-- packages/react/package.json | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 92bb9d86bf7..b70b75d2fd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5987,7 +5987,9 @@ } }, "node_modules/@primer/behaviors": { - "version": "1.7.2", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-1.8.0.tgz", + "integrity": "sha512-ZUfhWVY4ZBKc2Fh3fIa2Qwwa3SnOi914lY5wcmN+UNtsBxeXsjWNwpohJbwRwWZm+nJ3C1n9qJFWpHuBlDVU1A==", "license": "MIT" }, "node_modules/@primer/css": { @@ -29871,7 +29873,7 @@ "@github/tab-container-element": "^4.8.0", "@lit-labs/react": "1.2.1", "@oddbird/popover-polyfill": "^0.4.4", - "@primer/behaviors": "^1.7.2", + "@primer/behaviors": "^1.8.0", "@primer/live-region-element": "^0.7.1", "@primer/octicons-react": "^19.13.0", "@primer/primitives": "9.x || 10.x", diff --git a/packages/react/package.json b/packages/react/package.json index 1b889e3eaf8..19090b68718 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -83,7 +83,7 @@ "@github/tab-container-element": "^4.8.0", "@lit-labs/react": "1.2.1", "@oddbird/popover-polyfill": "^0.4.4", - "@primer/behaviors": "^1.7.2", + "@primer/behaviors": "^1.8.0", "@primer/live-region-element": "^0.7.1", "@primer/octicons-react": "^19.13.0", "@primer/primitives": "9.x || 10.x", From 20788daa3b80c3a332946abac8ab4c57cc9e3f35 Mon Sep 17 00:00:00 2001 From: Katie Langerman <18661030+langermank@users.noreply.github.com> Date: Tue, 21 Jan 2025 16:34:55 -0800 Subject: [PATCH 06/10] ActionBar: convert to CSS Modules + add new `flush` prop to adjust padding (#5540) * add props * fix border * fix type * remove label * try fix test? * Create shy-carpets-relax.md * test(vrt): update snapshots --------- Co-authored-by: langermank --- .changeset/shy-carpets-relax.md | 6 ++ ...onBar-CommentBox-dark-colorblind-linux.png | Bin 6721 -> 6714 bytes ...ActionBar-CommentBox-dark-dimmed-linux.png | Bin 6732 -> 6718 bytes ...ar-CommentBox-dark-high-contrast-linux.png | Bin 6818 -> 6805 bytes ...drafts-ActionBar-CommentBox-dark-linux.png | Bin 6721 -> 6714 bytes ...onBar-CommentBox-dark-tritanopia-linux.png | Bin 6721 -> 6714 bytes ...nBar-CommentBox-light-colorblind-linux.png | Bin 6684 -> 6677 bytes ...r-CommentBox-light-high-contrast-linux.png | Bin 6778 -> 6770 bytes ...rafts-ActionBar-CommentBox-light-linux.png | Bin 6684 -> 6677 bytes ...nBar-CommentBox-light-tritanopia-linux.png | Bin 6684 -> 6677 bytes .../react/src/ActionBar/ActionBar.docs.json | 14 +++ .../react/src/ActionBar/ActionBar.module.css | 35 ++++++ .../react/src/ActionBar/ActionBar.stories.tsx | 35 +++++- packages/react/src/ActionBar/ActionBar.tsx | 101 +++--------------- 14 files changed, 104 insertions(+), 87 deletions(-) create mode 100644 .changeset/shy-carpets-relax.md create mode 100644 packages/react/src/ActionBar/ActionBar.module.css diff --git a/.changeset/shy-carpets-relax.md b/.changeset/shy-carpets-relax.md new file mode 100644 index 00000000000..d58de136498 --- /dev/null +++ b/.changeset/shy-carpets-relax.md @@ -0,0 +1,6 @@ +--- +"@primer/react": minor +--- + +- Convert ActionBar to CSS Modules +- Add new padding prop for container padding diff --git a/.playwright/snapshots/components/drafts/ActionBar.test.ts-snapshots/drafts-ActionBar-CommentBox-dark-colorblind-linux.png b/.playwright/snapshots/components/drafts/ActionBar.test.ts-snapshots/drafts-ActionBar-CommentBox-dark-colorblind-linux.png index 653fb1c7cf28a5af799fff82e7a1748001bcc961..e83cc6e4e92f35fea431c9d1df04548cfe128f9a 100644 GIT binary patch delta 2965 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 delta 2984 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 delta 2990 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 Cz?#JX delta 3048 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 delta 2984 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 delta 2984 zcmai$X;_oT7RO&oy*ym5g0B}?XhEM?j7~EF4%lHiFUnX@S z4m@^hQop&+Vug@L1|I=H0eex_b?cUote&)hX~NSRX;WwG-*6&s!)^E`dsg(&E}ON(Z8Do^e8-QieIx3-B4-q+vg zM9~BOgj!ph%F3Q0trgfTmzy2#Q0MPRko_|KczLfF=3VY@+Vi(0Kb;-r8e&UORf zncmg!?#&1d0pR2vY)It@55Lj_YgM1x4ICG=&2P4=zxqCKaip#;h}7NPt>9uMhX)|D zo&aFTy3F>yQH6W%CkxBUJFm&tDM*=UF_s4^z3bzYtIe?}9v##f!CmR-&r|N&<(x%XMHnTm zIiv1a>$R1sU~Us{YEzvA)ZBCL0Ne8UiCzao@Ph4%PT4p2%JAxrR3lT{jbc#C85`bL zVgxua%)V8?n6x>c?U#cTFORjL^vl9QxrhJxSa!cXWvKvDyfNygQ^rV0%n~f4h@8({ zAOsf8Fak+((W082OzCZ`!E71L{M4(sgjZgms~!b-A(BVK{4`57UX~jFwQPcTwV&UV zCSv-zt_X50GV85#?eg8^HGa4ZuF5?_+%EL=@*+m%7zVdrW{2ub`pZsgD{v4cE3>*uWMJ^{Zh9N5T|Jv|a1AMd{Lx!b1p9hRORNjHv6HB(LTyYcmH9PQxYbRMbR+hjWhX@v6V_owY=u{>Cj#oWFbSU$Q-3|5lK9q6t% z&#mQ4T$jjG6iReh#ysU{JZJ3VJ|Y7z=-rIk7;VVvFS3K@K0kw_r(7Q}aFj}n}HOVCERu6mlb7U9FH5+uz;&~SJ*ZIE*RbYRb zD^1gv?~X{jI-wMT(^i&txl>raIzjh`m5$#J+)QLWY(r9`mTDhdxe0+^z z6L6GDBt}DG9xm6u!dMmAA!%{rtL82(^qxAC?Z*D-G9e$pZt91X{EXPG6eG1B$EFp=9M*yEPz+Y_K}3g!zsM zp;4yAM@TmXKVA@Vl+wY$yR$wu4`;p(=g#>J_A&5F{{$y~H-a$N*=KbUK)FRXS6gPVf1zryjTQ zsp@;j;)1Ce%&l)VHAXRgF<9ACwwqgj09Q8P{CI9h>V6>ttw0bty|hy2Zfy#YL2KB{ zDUO_xr!FF~WJ#BS#Wt5!>9C(np+IW1Bri|Ta{NLK44GMROR(N;?uhHGA*%b7@i)fCa3rlWyv}{~ zow1)eeWkYq+CPrlSoOK}O{r7zY`c&^iC3e_Qis`W*=wA_*upYy$@crH_j?KJ!|rM* z^2=voKq>jHrsUGO(5)V82`c=;4?Q-fw%g3jsq0gD{FVFZ-b@7!(TNGD`o%t^b6wg- zPXgZ;L_O4u^}U9&6f$Y%(PT@UnM+cCd}|oUmGQMBt<_5|H@DkpZ%>3KP*d9wQjG)z zmugUdZMxaSg8oySTE&yb1|#{p3_guE%f!uB!TNA#M9a%)6iNaKMvR}Y+Oyd_{g0^^ zY!Y!*jW`z1aTF7rkQ;A=B@VG*O3E}1E726@XG-A+c>|A1O`c_86cjkW6Ei#>D7X4j z?Aq#^e}sLsZ(qO(U$xScS)7K++4bxYz;W^6aMTCF;PzUYJUdJr)Fp|3UqBimBa!5w zoSYm9MZt?EjE^tfO%^g^KQX;w_Lp8oO9%n2AqF?IL+jB)#{=AziBJZ7Yqs*Mf+flv*Urm1@^n4G~YhV zmW=Lq@2+`83*XKCbYT?Zl`lUQe-OC216m=bNVLQOT!pn~Z1Y5gzS^(Uk+-nP(BHS@ zAojTgBkVluneEpSNQw-$K%}725fL}qc%?D`cz&ML3?bzF;V6Qulk1^FAvF&n8od4m z>#lfnU>*mfc^i$k5X022Ri~z;e2fwKjBN&X`cM%Lj*d58>E1aBOR=ld^^L@aJ((e_ z$52FVA~9W3Ge|@X3*eLDaD`?Y4Qxo z!nlyj_B?Ms_5c7Ll7o88#qgred#)L(kFkR%N&^VNrtMUB<)jZ8_rw7mUL9_qcf}g~ z9%#e+)!F9ZjGqU?1mxOqdq3lm?$5^Lm=kuXtGWo2r6D9P56acLJ?H^}|XPt*U zD z_WAx=gJcV0Atwr>y3`s0V zZPP^&L!FT8f!nb=a<)jWZ?OWD8^C z=RtN7x~$Y77Q>zY69CZ5X4NU+RITR`aG^Xzgh9QR`j%OQHl+6ZVpZ`N7JZF`1+UB% zorH#k+8yz$NEt8BAIwtEriU(Vb3!YQa4W!x`}rfaz67D?TKo_>L2TYjD=hnE4a|f& zUGF`4FKZ$nmW)8S%U>QbB`Iq9A@oHZA9QJ?pUXDD9Frn|%EN^pnuIcy0r8_5G)b6pLs^K+?q%5KX*9ogVLvLWY_N(| zta|CRO~rX;dTt-qRdiSE3MP;_7-1yp&C1m{=7fC15j^^Uy^@u=SFM=>)k~&1^;s)L z*p@G<5QERKNTwG=wita+*w8xnAs^bByz~ZVTi-HC0N0$f*Ln#sS7qOko*8eRBjw6W zsg?G;FV>Ol@ifd-p}#jOXE;KAN9cj>==41aHKo`CL&m4B@<1oHk%#Q!6aAUxU7A%#^ zp`nL}^>|2W%A_QmdSjy62=?o0>YLSQ`zPswmMud5(g&X|-})(SLXN{6^(PDE``kUA z9rHf+tzsD%^B2qrh~Jz7T4ONg%by2A=nEAV+UZ&EdL&zcv^iIPjrBBcG`*Pn7?n5^ zF$bls;4;IV<)7v*GNU!eK#=`{tT*=cr~&b%5D<6Dl(ag$NlXHt%>TUhUm``9>`Jsrs$jOHH3=@{BQ;6S>1#E9W~$dwa~XtiS{%ZU-9tV(rdf>kTF zT<_#V@SYq_7_%j5N?j&m!Ut5%*Y`9pNF^a@YUFP7teHErBU_nAzbsPM0UfC;ooas^ zi4-lEAzdW$hcYXfg2b@|^3hBoh*b0i7GiIO)7dSu(z{;%x^xW=nalJ|?Ucjx3H0Sk zMKv)?y;>JoAEp{;KVXE>*8I7%Q+Qn{x10HPSHzr^63d+PdQ+OFYEZ*c-tJs#ZB z=?-l3=4p56ysi(aF>}p0OK0EG)l~~EGXg1na|`P5g_F3OLZ*OdQN0unhfA`QyH2tt zmjvWneD`I0tozqfQH-YOE(S^|l(DF0S@^*PcX#&Bk!gKR4OO(=#Q1^#7-_g4!XiP% z)&9Nff#(J(+8?$G&xaX$skfpmIHRkdI_~ZETIw65s8_~CdzQ0?{s|a?#gMmk=y$2r z5VxRvuc2VxWK(yMD~Ia@M_<$MoU>7&F4+yq9i5))A*HEo^Czo(;dvxi+{@vHdag1O z^kEo#IBb z*L6z+2x9W|@^K?*OTrQkzm@UL536_!MT1IWb-;d@R{x^53*;-tLG7D@ouH_@wnEbm z0sryk=Mq$1&>n^F2~`e9=?I?{&mq4)#cthOHnoWiY^!m2nH`viyRmX=uw22JnsbD# zIVN*bd*M{b=FLHN#qvmG|M#Q;a{}`wSN6Ep@2LY%!fBm(5E$E<@#T3s;2-~rFzA-~ zxv$gRKR4;rtc`pV+=ht4Jnh(OVS5StCH{h z%M`_D-aYzrDl9a#Cng30EaG1T9FS(Xf`bdl&U6ZuLSaSi1#Vxw%VM#jUAVMNFl3dg!c(R#t9s3s0ifUCuDI0wyQ`!W z2>2c7`|7{l4`c5gvrK^iL-9T(2SZxYu99jk?>FfK@wPF3>H_P9FuNH&wO+dM2EdZn z9s^c_mDQ6)!QLaUz=}}285xD8rlX`!^#My(dkj-|9g2<;!wHHCe}{RCnnD@nu(?>L zW;9Os{Ec+*7w5q~| zlGL@fwzjvMrb^w-ozIX%;Y~skT-iI5S{F*VfG2P2Dws_|B*N=P@jqhgNi_ff delta 2912 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 diff --git a/.playwright/snapshots/components/drafts/ActionBar.test.ts-snapshots/drafts-ActionBar-CommentBox-light-high-contrast-linux.png b/.playwright/snapshots/components/drafts/ActionBar.test.ts-snapshots/drafts-ActionBar-CommentBox-light-high-contrast-linux.png index 33d8414bac3e603c172dc4704dbe896cc391bf6f..f71ffeff64d0f274527746044ac6f466437672d9 100644 GIT binary patch delta 3031 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 delta 2912 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 diff --git a/.playwright/snapshots/components/drafts/ActionBar.test.ts-snapshots/drafts-ActionBar-CommentBox-light-tritanopia-linux.png b/.playwright/snapshots/components/drafts/ActionBar.test.ts-snapshots/drafts-ActionBar-CommentBox-light-tritanopia-linux.png index dcdff2e7e1d3a039cda31924735fc68a0b8d2d65..e1519ddc421f050cf80287a960df89bb26f0a923 100644 GIT binary patch delta 2907 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 delta 2912 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 diff --git a/packages/react/src/ActionBar/ActionBar.docs.json b/packages/react/src/ActionBar/ActionBar.docs.json index 878a96eafe2..c658ac11d1f 100644 --- a/packages/react/src/ActionBar/ActionBar.docs.json +++ b/packages/react/src/ActionBar/ActionBar.docs.json @@ -37,6 +37,20 @@ "required": false, "description": "Size of the action bar", "defaultValue": "" + }, + { + "name": "flush", + "type": "boolean", + "required": false, + "description": "Allows ActionBar to be flush with the container", + "defaultValue": "false" + }, + { + "name": "className", + "type": "string", + "required": false, + "description": "Custom className", + "defaultValue": "" } ], "subcomponents": [ diff --git a/packages/react/src/ActionBar/ActionBar.module.css b/packages/react/src/ActionBar/ActionBar.module.css new file mode 100644 index 00000000000..d795c7b57a8 --- /dev/null +++ b/packages/react/src/ActionBar/ActionBar.module.css @@ -0,0 +1,35 @@ +.List { + position: relative; + display: flex; + min-width: 0; + + /* wonder why this is here */ + /* stylelint-disable-next-line primer/spacing */ + margin-bottom: -1px; + white-space: nowrap; + list-style: none; + align-items: center; + gap: var(--base-size-8); +} + +.Nav { + display: flex; + padding-inline: var(--base-size-16); + justify-content: flex-end; + align-items: center; + + &:where([data-flush='true']) { + padding-inline: 0; + } +} + +.Divider { + &::before { + display: block; + width: var(--borderWidth-thin); + height: var(--base-size-20); + content: ''; + /* stylelint-disable-next-line primer/colors */ + background: var(--borderColor-muted); + } +} diff --git a/packages/react/src/ActionBar/ActionBar.stories.tsx b/packages/react/src/ActionBar/ActionBar.stories.tsx index 7314dd64f80..75c6c2a1486 100644 --- a/packages/react/src/ActionBar/ActionBar.stories.tsx +++ b/packages/react/src/ActionBar/ActionBar.stories.tsx @@ -1,5 +1,4 @@ import React from 'react' -import type {Meta} from '@storybook/react' import ActionBar from '.' import { BoldIcon, @@ -13,11 +12,43 @@ import { ListOrderedIcon, TasklistIcon, } from '@primer/octicons-react' +import type {Meta, StoryObj} from '@storybook/react' -export default { +const meta: Meta = { title: 'Experimental/Components/ActionBar', } as Meta +export default meta +type Story = StoryObj + +export const Playground: Story = { + render: args => ( + + + + + + + ), +} +Playground.argTypes = { + size: { + control: { + type: 'radio', + }, + options: ['small', 'medium', 'large'], + }, + flush: { + control: { + type: 'boolean', + }, + }, +} +Playground.args = { + size: 'medium', + flush: false, +} + export const Default = () => ( diff --git a/packages/react/src/ActionBar/ActionBar.tsx b/packages/react/src/ActionBar/ActionBar.tsx index 244539e98a7..8740c89673c 100644 --- a/packages/react/src/ActionBar/ActionBar.tsx +++ b/packages/react/src/ActionBar/ActionBar.tsx @@ -3,8 +3,6 @@ import React, {useState, useCallback, useRef, forwardRef} from 'react' import {KebabHorizontalIcon} from '@primer/octicons-react' import {ActionList} from '../ActionList' import useIsomorphicLayoutEffect from '../utils/useIsomorphicLayoutEffect' -import styled from 'styled-components' -import sx from '../sx' import {useOnEscapePress} from '../hooks/useOnEscapePress' import type {ResizeObserverEntry} from '../hooks/useResizeObserver' import {useResizeObserver} from '../hooks/useResizeObserver' @@ -12,9 +10,10 @@ import {useResizeObserver} from '../hooks/useResizeObserver' import {useOnOutsideClick} from '../hooks/useOnOutsideClick' import type {IconButtonProps} from '../Button' import {IconButton} from '../Button' -import Box from '../Box' import {ActionMenu} from '../ActionMenu' import {useFocusZone, FocusKeys} from '../hooks/useFocusZone' +import styles from './ActionBar.module.css' +import {clsx} from 'clsx' type ChildSize = { text: string @@ -43,54 +42,13 @@ type A11yProps = export type ActionBarProps = { size?: Size children: React.ReactNode + flush?: boolean + className?: string } & A11yProps export type ActionBarIconButtonProps = IconButtonProps -const NavigationList = styled.div` - ${sx}; -` - -const GAP = 8 - -const listStyles = { - display: 'flex', - minWidth: 0, - listStyle: 'none', - whiteSpace: 'nowrap', - paddingY: 0, - paddingX: 0, - margin: 0, - marginBottom: '-1px', - alignItems: 'center', - gap: `${GAP}px`, - position: 'relative', -} - const MORE_BTN_WIDTH = 86 -const navStyles = { - display: 'flex', - paddingX: 3, - justifyContent: 'flex-end', - align: 'row', - alignItems: 'center', - maxHeight: '32px', -} - -const menuItemStyles = { - textDecoration: 'none', -} - -const moreBtnStyles = { - //set margin 0 here because safari puts extra margin around the button, rest is to reset style to make it look like a list element - margin: 0, - border: 0, - background: 'transparent', - fontWeight: 'normal', - boxShadow: 'none', - paddingY: 1, - paddingX: 2, -} const getValidChildren = (children: React.ReactNode) => { return React.Children.toArray(children).filter(child => { @@ -168,7 +126,7 @@ const overflowEffect = ( } export const ActionBar: React.FC> = props => { - const {size = 'medium', children, 'aria-label': ariaLabel} = props + const {size = 'medium', children, 'aria-label': ariaLabel, flush = false, className} = props const [childWidthArray, setChildWidthArray] = useState([]) const setChildrenWidth = useCallback((size: ChildSize) => { setChildWidthArray(arr => { @@ -243,13 +201,13 @@ export const ActionBar: React.FC> = prop return ( - - +
+
{listItems} {menuItems.length > 0 && ( - + @@ -257,20 +215,11 @@ export const ActionBar: React.FC> = prop if (menuItem.type === ActionList.Divider) { return } else { - const { - children: menuItemChildren, - //'aria-current': ariaCurrent, - onClick, - icon: Icon, - 'aria-label': ariaLabel, - } = menuItem.props + const {children: menuItemChildren, onClick, icon: Icon, 'aria-label': ariaLabel} = menuItem.props return ( - | React.KeyboardEvent, - ) => { + onClick={(event: React.MouseEvent) => { closeOverlay() focusOnMoreMenuBtn() typeof onClick === 'function' && onClick(event) @@ -282,7 +231,7 @@ export const ActionBar: React.FC> = prop ) : null} {ariaLabel} - + ) } })} @@ -290,8 +239,8 @@ export const ActionBar: React.FC> = prop )} - - +
+
) } @@ -308,31 +257,13 @@ export const ActionBarIconButton = forwardRef((props: ActionBarIconButtonProps, return }) -const sizeToHeight = { - small: '24px', - medium: '28px', - large: '32px', -} export const VerticalDivider = () => { const ref = useRef(null) - const {size, setChildrenWidth} = React.useContext(ActionBarContext) + const {setChildrenWidth} = React.useContext(ActionBarContext) useIsomorphicLayoutEffect(() => { const text = 'divider' const domRect = (ref as MutableRefObject).current.getBoundingClientRect() setChildrenWidth({text, width: domRect.width}) }, [ref, setChildrenWidth]) - return ( -