From 5e51b3e6d5151fc3c451531085ca0504eb5c1e16 Mon Sep 17 00:00:00 2001 From: Gabriel Pereira Pinheiro Date: Mon, 3 Feb 2025 08:49:48 -0800 Subject: [PATCH] RadioGroup: VR changes (#3968) --- docs/docs-components/siteIndex.ts | 1 - packages/gestalt/src/Borders.css | 10 ++ packages/gestalt/src/Fieldset.tsx | 32 +++++++ packages/gestalt/src/Fieldset/VRFieldset.css | 3 + packages/gestalt/src/Fieldset/VRFieldset.tsx | 91 +++++++++++++++++++ packages/gestalt/src/RadioButton.css | 12 +++ packages/gestalt/src/RadioGroup.tsx | 26 +++++- packages/gestalt/src/RadioGroupButton.tsx | 22 ++++- .../sharedSubcomponents/FormErrorMessage.tsx | 3 + .../sharedSubcomponents/FormHelperText.css | 4 + .../sharedSubcomponents/FormHelperText.tsx | 3 + 11 files changed, 199 insertions(+), 8 deletions(-) create mode 100644 packages/gestalt/src/Fieldset/VRFieldset.css create mode 100644 packages/gestalt/src/Fieldset/VRFieldset.tsx diff --git a/docs/docs-components/siteIndex.ts b/docs/docs-components/siteIndex.ts index 91fb8daee2..544f81422a 100644 --- a/docs/docs-components/siteIndex.ts +++ b/docs/docs-components/siteIndex.ts @@ -168,7 +168,6 @@ const siteIndex: readonly [siteIndexType, ...siteIndexType[]] = [ 'Popover', 'PopoverEducational', 'Pulsar', - 'RadioButton', 'RadioGroup', 'SearchField', 'SearchGuide', diff --git a/packages/gestalt/src/Borders.css b/packages/gestalt/src/Borders.css index c0bf79f151..ec518dae85 100644 --- a/packages/gestalt/src/Borders.css +++ b/packages/gestalt/src/Borders.css @@ -1,6 +1,8 @@ :root { --g-border-width: 1px; --g-border-width-lg: 2px; + --g-border-width-lg-vr: 1px; + --g-border-width-lg-vr-hover: 1.5px; } /* Border lines */ @@ -119,6 +121,14 @@ html[dir="rtl"] .borderLeft { border-width: var(--g-border-width-lg); } +.sizeLgVR { + border-width: var(--g-border-width-lg-vr); +} + +.sizeLgHoverVR { + border-width: var(--g-border-width-lg-vr-hover); +} + .solid { border-style: solid; } diff --git a/packages/gestalt/src/Fieldset.tsx b/packages/gestalt/src/Fieldset.tsx index 226db96358..518a747a14 100644 --- a/packages/gestalt/src/Fieldset.tsx +++ b/packages/gestalt/src/Fieldset.tsx @@ -2,9 +2,11 @@ import { ReactNode } from 'react'; import classnames from 'classnames'; import boxStyles from './Box.css'; import boxWhitespaceStyles from './boxWhitespace.css'; +import VRFieldset from './Fieldset/VRFieldset'; import labelStyles from './Label/InternalLabel.css'; import formStyles from './sharedSubcomponents/FormElement.css'; import FormErrorMessage from './sharedSubcomponents/FormErrorMessage'; +import FormHelperText from './sharedSubcomponents/FormHelperText'; import formLabelStyles from './sharedSubcomponents/FormLabel.css'; import Text from './Text'; import useInExperiment from './useInExperiment'; @@ -31,6 +33,11 @@ type Props = { * Whether the legend should be visible or not. If `hidden`, the legend is still available for screen reader users, but does not appear visually. See the [legend visibility variant](https://gestalt.pinterest.systems#Legend-visibility) for more info. */ legendDisplay?: 'visible' | 'hidden'; + /** + * Adds an help message below the group of radio buttons. + * + */ + helperText?: string; }; /** @@ -46,6 +53,7 @@ export default function Fieldset({ legend, legendDisplay = 'visible', children, + helperText, }: Props) { const isInVRExperiment = useInExperiment({ webExperimentName: 'web_gestalt_visualrefresh', @@ -57,6 +65,20 @@ export default function Fieldset({ console.error('Please provide an id property to
'); } + if (isInVRExperiment) { + return ( + + {children} + + ); + } + return (
{legend} {children} + {helperText && ( + + )} + {errorMessage && }
); diff --git a/packages/gestalt/src/Fieldset/VRFieldset.css b/packages/gestalt/src/Fieldset/VRFieldset.css new file mode 100644 index 0000000000..3f8ec79414 --- /dev/null +++ b/packages/gestalt/src/Fieldset/VRFieldset.css @@ -0,0 +1,3 @@ +.marginBottom { + margin-bottom: var(--sema-space-200); +} diff --git a/packages/gestalt/src/Fieldset/VRFieldset.tsx b/packages/gestalt/src/Fieldset/VRFieldset.tsx new file mode 100644 index 0000000000..0e0cd39ff3 --- /dev/null +++ b/packages/gestalt/src/Fieldset/VRFieldset.tsx @@ -0,0 +1,91 @@ +import { ReactNode } from 'react'; +import classnames from 'classnames'; +import fieldsetStyles from './VRFieldset.css'; +import boxStyles from '../Box.css'; +import boxWhitespaceStyles from '../boxWhitespace.css'; +import labelStyles from '../Label/InternalLabel.css'; +import formStyles from '../sharedSubcomponents/FormElement.css'; +import FormErrorMessage from '../sharedSubcomponents/FormErrorMessage'; +import FormHelperText from '../sharedSubcomponents/FormHelperText'; +import Text from '../Text'; +import whitespaceStyles from '../Whitespace.css'; + +type Props = { + /** + * The content of Fieldset, typically [RadioButtons](https://gestalt.pinterest.systems/web/radiobutton), [Checkboxes](https://gestalt.pinterest.systems/web/checkbox) or [TextFields](https://gestalt.pinterest.systems/web/textfield). + */ + children: ReactNode; + /** + * A unique identifier for this Fieldset. `id` must be specified when an errorMessage is added. + */ + id?: string; + /** + * When needed, pass a string with a helpful error message (be sure to localize!). + */ + errorMessage?: string; + /** + * Caption that clearly and concisely describes the form elements grouped in the fieldset. + */ + legend: string; + /** + * Whether the legend should be visible or not. If `hidden`, the legend is still available for screen reader users, but does not appear visually. See the [legend visibility variant](https://gestalt.pinterest.systems#Legend-visibility) for more info. + */ + legendDisplay?: 'visible' | 'hidden'; + /** + * Adds an help message below the group of radio buttons. + */ + helperText?: string; +}; + +/** + * [Fieldset](https://gestalt.pinterest.systems/web/fieldset) creates a fieldset and legend for a group of related form items, like [RadioButtons](https://gestalt.pinterest.systems/web/radiobutton) or [CheckBoxes](https://gestalt.pinterest.systems/web/checkbox), in order to clearly indicate related form items." + * + * ![Fieldset light mode](https://raw.githubusercontent.com/pinterest/gestalt/master/playwright/visual-test/Fieldset.spec.ts-snapshots/Fieldset-chromium-darwin.png) + * ![Fieldset dark mode](https://raw.githubusercontent.com/pinterest/gestalt/master/playwright/visual-test/Fieldset-dark.spec.ts-snapshots/Fieldset-dark-chromium-darwin.png) + * + */ +export default function VRFieldset({ + id = '', + errorMessage, + legend, + legendDisplay = 'visible', + children, + helperText, +}: Props) { + if (errorMessage && id === '') { + // eslint-disable-next-line no-console + console.error('Please provide an id property to
'); + } + + return ( +
+ + {legend} + + {children} + {helperText && ( + + )} + + {errorMessage && } +
+ ); +} diff --git a/packages/gestalt/src/RadioButton.css b/packages/gestalt/src/RadioButton.css index f6893fc199..c4c201a10f 100644 --- a/packages/gestalt/src/RadioButton.css +++ b/packages/gestalt/src/RadioButton.css @@ -46,10 +46,22 @@ composes: sizeLg from "./Borders.css"; } +.BorderUncheckedVR { + composes: sizeLgVR from "./Borders.css"; +} + +.BorderUncheckedHoverVR { + composes: sizeLgHoverVR from "./Borders.css"; +} + .BgDisabled { background-color: var(--color-background-formfield-disabled); } +.BgDisabledVR { + background-color: var(--sema-color-background-disabled); +} + .BgEnabled { background-color: var(--color-background-formfield-primary); } diff --git a/packages/gestalt/src/RadioGroup.tsx b/packages/gestalt/src/RadioGroup.tsx index 20dbfd1968..8573461f57 100644 --- a/packages/gestalt/src/RadioGroup.tsx +++ b/packages/gestalt/src/RadioGroup.tsx @@ -4,6 +4,7 @@ import Fieldset from './Fieldset'; import Flex from './Flex'; import { RadioGroupContextProvider } from './RadioGroup/Context'; import RadioGroupButton from './RadioGroupButton'; +import useInExperiment from './useInExperiment'; type Props = { /** @@ -36,6 +37,11 @@ type Props = { * */ legendDisplay?: 'visible' | 'hidden'; + /** + * Adds an help message below the group of radio buttons. + * + */ + helperText?: string; }; /** @@ -49,22 +55,38 @@ function RadioGroup({ id, legend, legendDisplay = 'visible', + helperText, }: Props) { // Consume GlobalEventsHandlerProvider const { radioGroupHandlers } = useGlobalEventsHandlerContext() ?? { radioGroupHandlers: undefined, }; + const isInVRExperiment = useInExperiment({ + webExperimentName: 'web_gestalt_visualrefresh', + mwebExperimentName: 'web_gestalt_visualrefresh', + }); + useEffect(() => { if (radioGroupHandlers?.onRender) radioGroupHandlers?.onRender(); }, [radioGroupHandlers]); return ( -
+
{children} diff --git a/packages/gestalt/src/RadioGroupButton.tsx b/packages/gestalt/src/RadioGroupButton.tsx index acb7adf29b..e4a432433a 100644 --- a/packages/gestalt/src/RadioGroupButton.tsx +++ b/packages/gestalt/src/RadioGroupButton.tsx @@ -127,11 +127,11 @@ const RadioGroupButtonWithForwardRef = forwardRef(funct borderColor = styles.BorderDisabledChecked; } else if (!disabled && checked) { borderColor = styles.BorderSelected; - } else if (!disabled && hovered) { + } else if (!disabled && hovered && !isInVRExperiment) { borderColor = styles.BorderHovered; } - let borderWidth = styles.BorderUnchecked; + let borderWidth = isInVRExperiment ? styles.BorderUncheckedVR : styles.BorderUnchecked; if (disabled && !checked) { borderWidth = styles.BorderDisabled; } else if (checked && size === 'sm') { @@ -140,11 +140,20 @@ const RadioGroupButtonWithForwardRef = forwardRef(funct borderWidth = styles.BorderCheckedMd; } - const uncheckedBorderWidth = disabled ? styles.BorderDisabled : styles.BorderUnchecked; + let uncheckedBorderWidth = styles.BorderDisabled; + + if (!isInVRExperiment) { + uncheckedBorderWidth = disabled ? styles.BorderDisabled : styles.BorderUnchecked; + } else { + uncheckedBorderWidth = !disabled ? styles.BorderUncheckedVR : uncheckedBorderWidth; + uncheckedBorderWidth = + hovered && !disabled ? styles.BorderUncheckedHoverVR : styles.BorderUncheckedVR; + } const styleSize = size === 'sm' ? controlStyles.sizeSm : controlStyles.sizeMd; - const bgStyle = disabled && !checked ? styles.BgDisabled : styles.BgEnabled; + let bgStyle = disabled && !checked ? styles.BgDisabled : styles.BgEnabled; + bgStyle = isInVRExperiment && !checked ? styles.BgDisabledVR : bgStyle; const { isFocusVisible } = useFocusVisible(); @@ -182,6 +191,9 @@ const RadioGroupButtonWithForwardRef = forwardRef(funct }, ); + let margin = size === 'md' ? '2px' : '-1px'; + margin = isInVRExperiment ? '0px' : margin; + return ( @@ -232,7 +244,7 @@ const RadioGroupButtonWithForwardRef = forwardRef(funct {/* marginTop: '-1px'/'2px' is needed to visually align the label text & radiobutton input */} diff --git a/packages/gestalt/src/sharedSubcomponents/FormErrorMessage.tsx b/packages/gestalt/src/sharedSubcomponents/FormErrorMessage.tsx index 59b2b8f13a..c6add43997 100644 --- a/packages/gestalt/src/sharedSubcomponents/FormErrorMessage.tsx +++ b/packages/gestalt/src/sharedSubcomponents/FormErrorMessage.tsx @@ -15,6 +15,7 @@ type Props = { text?: ReactNode; size?: SizeType; noPadding?: boolean; + marginTop?: boolean; }; export default function FormErrorMessage({ @@ -22,6 +23,7 @@ export default function FormErrorMessage({ size, text = '', noPadding: noStartPadding, + marginTop, }: Props) { const isInVRExperiment = useInExperiment({ webExperimentName: 'web_gestalt_visualrefresh', @@ -31,6 +33,7 @@ export default function FormErrorMessage({ return (