diff --git a/docs/docs-components/App.tsx b/docs/docs-components/App.tsx index 9f21599042..3874578e72 100644 --- a/docs/docs-components/App.tsx +++ b/docs/docs-components/App.tsx @@ -75,13 +75,15 @@ export default function App({ children, files }: Props) { {({ colorScheme }) => ( - - - - {children} - - - + + + + + {children} + + + + )} diff --git a/docs/docs-components/Header.tsx b/docs/docs-components/Header.tsx index 0c8186d5ed..b2987ddca8 100644 --- a/docs/docs-components/Header.tsx +++ b/docs/docs-components/Header.tsx @@ -40,17 +40,26 @@ function getTabs(componentPlatform: 'web' | 'android' | 'ios') { } function Header() { + const searchAnchorRef = useRef(null); + const router = useRouter(); const { isSidebarOpen, setIsSidebarOpen, componentPlatformFilteredBy } = useNavigationContext(); const [isMobileSearchExpandedOpen, setMobileSearchExpanded] = useState(false); - const [showVRToggle, setShowVRToggle] = useState(false); - const searchAnchorRef = useRef(null); + const [showVRToggle, setShowVRToggle] = useState(false); const isInVRExperiment = useDangerouslyInGestaltExperiment({ webExperimentName: 'web_gestalt_visualRefresh', mwebExperimentName: 'web_gestalt_visualRefresh', }); + + const [showVR1Toggle, setShowVR1Toggle] = useState(false); + + const isInVR1Experiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh1', + mwebExperimentName: 'web_gestalt_visualRefresh1', + }); + const { setExperiments } = useAppContext(); const mainNavigationTabs = useMemo( @@ -85,8 +94,16 @@ function Header() { ); useEffect(() => { - if (isInVRExperiment) setShowVRToggle(true); - }, [isInVRExperiment]); + if (isInVRExperiment) { + setShowVRToggle(true); + setShowVR1Toggle(false); + } + + if (isInVR1Experiment) { + setShowVRToggle(false); + setShowVR1Toggle(true); + } + }, [isInVRExperiment, isInVR1Experiment]); useEffect(() => { const isDeployPreviewEnvironment = @@ -205,6 +222,16 @@ function Header() { /> )} + {showVR1Toggle && ( + setExperiments(isInVR1Experiment ? '' : 'VR1')} + selected={isInVR1Experiment} + size="sm" + text={isInVR1Experiment ? 'VR1 on' : 'VR1 off'} + /> + )} + {devExampleMode === 'development' ? ( + + + + } name="Visual refresh experimentation" type="guidelines" diff --git a/packages/gestalt/src/Button.tsx b/packages/gestalt/src/Button.tsx index c0b9de83c3..0cce360c71 100644 --- a/packages/gestalt/src/Button.tsx +++ b/packages/gestalt/src/Button.tsx @@ -3,6 +3,7 @@ import classnames from 'classnames'; import NewTabAccessibilityLabel from './accessibility/NewTabAccessibilityLabel'; import styles from './Button.css'; import { useColorScheme } from './contexts/ColorSchemeProvider'; +import ExperimentProvider from './contexts/ExperimentProvider'; import Flex from './Flex'; import focusStyles from './Focus.css'; import Icon, { IconColor } from './Icon'; @@ -140,13 +141,16 @@ function InternalButtonContent({ mwebExperimentName: 'web_gestalt_visualRefresh', }); + const isInVR1 = useInExperiment({ + webExperimentName: 'web_gestalt_visualRefresh1', + mwebExperimentName: 'web_gestalt_visualRefresh1', + }); + + const isInVR = isInVR1 || isInVRExperiment; + return ( - + {iconStart && ( (function Butto mwebExperimentName: 'web_gestalt_visualRefresh', }); + const isInVR1 = useInExperiment({ + webExperimentName: 'web_gestalt_visualRefresh1', + mwebExperimentName: 'web_gestalt_visualRefresh1', + }); + + const isInVR = isInVR1 || isInVRExperiment; + const textSizes: { [key: string]: '100' | '200' | '300' | '400' | '500' | '600'; } = { @@ -250,12 +261,12 @@ const ButtonWithForwardRef = forwardRef(function Butto const isDarkMode = colorSchemeName === 'darkMode'; const isDarkModeRed = isDarkMode && color === 'red'; - const colorClass = color === 'transparentWhiteText' && !isInVRExperiment ? 'transparent' : color; + const colorClass = color === 'transparentWhiteText' && !isInVR ? 'transparent' : color; const { isFocusVisible } = useFocusVisible(); - const sharedTypeClasses = isInVRExperiment - ? classnames(styles.buttonVr, { + const sharedTypeClasses = isInVR + ? classnames('visualRefreshA', styles.buttonVr, { [styles.smVr]: size === 'sm', [styles.mdVr]: size === 'md', [styles.lgVr]: size === 'lg', @@ -273,7 +284,7 @@ const ButtonWithForwardRef = forwardRef(function Butto [focusStyles.accessibilityOutline]: !disabled && isFocusVisible, }); - const baseTypeClasses = isInVRExperiment + const baseTypeClasses = isInVR ? classnames(sharedTypeClasses, touchableStyles.tapTransition, { [styles.selected]: !disabled && selected, [styles.disabled]: disabled, @@ -294,7 +305,7 @@ const ButtonWithForwardRef = forwardRef(function Butto const parentButtonClasses = classnames( sharedTypeClasses, styles.parentButton, - isInVRExperiment && { + isInVR && { [styles[colorClass]]: !disabled && !selected, }, ); @@ -305,10 +316,10 @@ const ButtonWithForwardRef = forwardRef(function Butto (disabled && 'disabled') || (selected && 'inverse') || (isDarkModeRed && 'default') || - (isInVRExperiment && isDarkMode && color === 'blue' && 'default') || + (isInVR && isDarkMode && color === 'blue' && 'default') || DEFAULT_TEXT_COLORS[color]; - const buttonText = isInVRExperiment ? ( + const buttonText = isInVR ? ( {text} @@ -342,12 +353,27 @@ const ButtonWithForwardRef = forwardRef(function Butto tabIndex={disabled ? null : tabIndex} type="submit" > - + {isInVR1 ? ( + + + + ) : ( + + )} ); } @@ -373,24 +399,46 @@ const ButtonWithForwardRef = forwardRef(function Butto onTouchMove={handleTouchMove} // @ts-expect-error - TS2322 - Type '(arg1: TouchEvent) => void' is not assignable to type 'TouchEventHandler'. onTouchStart={handleTouchStart} - style={isInVRExperiment ? compressStyle || undefined : undefined} + style={isInVR ? compressStyle || undefined : undefined} // @ts-expect-error - TS2322 - Type '0 | -1 | null' is not assignable to type 'number | undefined'. tabIndex={disabled ? null : tabIndex} type="button" > -
- {iconEnd || iconStart ? ( - - ) : ( - buttonText - )} -
+ {isInVR1 ? ( + +
+ {iconEnd || iconStart ? ( + + ) : ( + buttonText + )} +
+
+ ) : ( +
+ {iconEnd || iconStart ? ( + + ) : ( + buttonText + )} +
+ )} ); }); diff --git a/packages/gestalt/src/Text.tsx b/packages/gestalt/src/Text.tsx index cdb1b73129..bee37f7bc7 100644 --- a/packages/gestalt/src/Text.tsx +++ b/packages/gestalt/src/Text.tsx @@ -1,5 +1,6 @@ import { forwardRef, ReactElement, ReactNode } from 'react'; import cx from 'classnames'; +import ExperimentProvider from './contexts/ExperimentProvider'; import styles from './Text.css'; import { semanticColors } from './textTypes'; import typographyStyle from './Typography.css'; @@ -110,6 +111,12 @@ const TextWithForwardRef = forwardRef(function Text( mwebExperimentName: 'web_gestalt_visualRefresh', }); + const isInVR1 = useInExperiment({ + webExperimentName: 'web_gestalt_visualRefresh1', + mwebExperimentName: 'web_gestalt_visualRefresh1', + }); + + const isInVR = isInVR1 || isInVRExperiment; const getWordBreakStyle = (): string | undefined => { if (overflow === 'breakAll') { return typographyStyle.breakAll; @@ -124,6 +131,7 @@ const TextWithForwardRef = forwardRef(function Text( }; const cs = cx( + 'visualRefreshA', color && colorClass, align === 'center' && typographyStyle.alignCenter, // @ts-expect-error - TS2367 - This condition will always return 'false' since the types '"center" | "start" | "end" | "forceLeft" | "forceRight"' and '"justify"' have no overlap. @@ -138,29 +146,25 @@ const TextWithForwardRef = forwardRef(function Text( underline && styles.underline, isNotNullish(lineClamp) && typographyStyle.lineClamp, { - [styles.Text]: !isInVRExperiment, - [typographyStyle[`fontSize${size}`]]: !isInVRExperiment, - [typographyStyle.fontWeightSemiBold]: !isInVRExperiment && weight === 'bold', - [typographyStyle.fontWeightNormal]: !isInVRExperiment && weight === 'normal', - [styles.TextBody]: isInVRExperiment, - [styles.lg]: isInVRExperiment && (size === '400' || size === '500' || size === '600'), - [styles.md]: isInVRExperiment && size === '300', - [styles.sm]: isInVRExperiment && size === '200', - [styles.xs]: isInVRExperiment && size === '100', + [styles.Text]: !isInVR, + [typographyStyle[`fontSize${size}`]]: !isInVR, + [typographyStyle.fontWeightSemiBold]: !isInVR && weight === 'bold', + [typographyStyle.fontWeightNormal]: !isInVR && weight === 'normal', + [styles.TextBody]: isInVR, + [styles.lg]: isInVR && (size === '400' || size === '500' || size === '600'), + [styles.md]: isInVR && size === '300', + [styles.sm]: isInVR && size === '200', + [styles.xs]: isInVR && size === '100', [styles.lgDefault]: - isInVRExperiment && - (size === '400' || size === '500' || size === '600') && - weight === 'normal', - [styles.mdDefault]: isInVRExperiment && size === '300' && weight === 'normal', - [styles.smDefault]: isInVRExperiment && size === '200' && weight === 'normal', - [styles.xsDefault]: isInVRExperiment && size === '100' && weight === 'normal', + isInVR && (size === '400' || size === '500' || size === '600') && weight === 'normal', + [styles.mdDefault]: isInVR && size === '300' && weight === 'normal', + [styles.smDefault]: isInVR && size === '200' && weight === 'normal', + [styles.xsDefault]: isInVR && size === '100' && weight === 'normal', [styles.lgEmphasis]: - isInVRExperiment && - (size === '400' || size === '500' || size === '600') && - weight === 'bold', - [styles.mdEmphasis]: isInVRExperiment && size === '300' && weight === 'bold', - [styles.smEmphasis]: isInVRExperiment && size === '200' && weight === 'bold', - [styles.xsEmphasis]: isInVRExperiment && size === '100' && weight === 'bold', + isInVR && (size === '400' || size === '500' || size === '600') && weight === 'bold', + [styles.mdEmphasis]: isInVR && size === '300' && weight === 'bold', + [styles.smEmphasis]: isInVR && size === '200' && weight === 'bold', + [styles.xsEmphasis]: isInVR && size === '100' && weight === 'bold', }, ); @@ -176,7 +180,17 @@ const TextWithForwardRef = forwardRef(function Text( {...(lineClamp ? { style: { WebkitLineClamp: lineClamp } } : {})} ref={ref} > - {children} + {isInVR1 ? ( + + {children} + + ) : ( + children + )} ); }); diff --git a/packages/gestalt/src/contexts/ColorSchemeProvider.tsx b/packages/gestalt/src/contexts/ColorSchemeProvider.tsx index 92d67cfbda..7e2d5d2800 100644 --- a/packages/gestalt/src/contexts/ColorSchemeProvider.tsx +++ b/packages/gestalt/src/contexts/ColorSchemeProvider.tsx @@ -137,6 +137,10 @@ type Props = { * Sets the line height for the selected language. */ language?: 'default' | 'tall' | 'ck' | 'ja' | 'th' | 'vi'; + /** + * Undocumented prop to enable omitting provider unless second condition is met. + */ + _conditionallyInactive?: boolean; }; /** @@ -148,17 +152,25 @@ export default function ColorSchemeProvider({ fullDimensions = false, id, language = 'default', + _conditionallyInactive = false, }: Props) { const [theme, setTheme] = useState(getTheme(colorScheme)); const [languageLineHeight, setLanguageLineHeight] = useState(language); - const className = id ? `__gestaltTheme${id}` : undefined; - const selector = className ? `.${className}` : ':root'; const isInExperiment = useInExperiment({ webExperimentName: 'web_gestalt_visualRefresh', mwebExperimentName: 'web_gestalt_visualRefresh', }); + const isInExperiment1 = useInExperiment({ + webExperimentName: 'web_gestalt_visualRefresh1', + mwebExperimentName: 'web_gestalt_visualRefresh1', + }); + + const className = id ? `__gestaltTheme${id}` : undefined; + const rootSelector = + isInExperiment1 && _conditionallyInactive ? ':root .visualRefreshA' : ':root'; + const selector = className ? `.${className}` : rootSelector; const handlePrefChange = (event: MediaQueryList) => { setTheme(getTheme(event.matches ? 'dark' : 'light')); }; @@ -176,6 +188,8 @@ export default function ColorSchemeProvider({ return undefined; // Flow doesn't like that only userPreference returns a clean up func }, [colorScheme, language]); + if (!isInExperiment1 && _conditionallyInactive) return children; + return (