diff --git a/docs/6.x/docs/guides/migration.md b/docs/6.x/docs/guides/migration.md index 72aee6d00f..84cb793efb 100644 --- a/docs/6.x/docs/guides/migration.md +++ b/docs/6.x/docs/guides/migration.md @@ -307,6 +307,48 @@ The misspelled `traileringIcon` props have been renamed: /> ``` +### FAB + +To preserve the v5 FAB color treatment, update the `variant` prop: + +| v5 | v6 | +| ----------- | -------------------- | +| `primary` | `primaryContainer` | +| `secondary` | `secondaryContainer` | +| `tertiary` | `tertiaryContainer` | + +If you omit `variant`, no change is needed. The `surface` variant was removed. To keep its look, pass the colors directly: + +```jsx +import { FAB, useTheme } from 'react-native-paper'; + +const MyFAB = () => { + const { colors } = useTheme(); + + return ( + + ); +}; +``` + +For custom colors, replace `color` with `contentColor` and move +`style.backgroundColor` to `containerColor`: + +```diff + +``` + ### TextInput The Paper 6.x `TextInput` is a complete rewrite with a new API. Import the component the same way, but note that the props and behavior have changed significantly. diff --git a/example/src/Examples/FABExample.tsx b/example/src/Examples/FABExample.tsx index 09ce39aa14..e6470cc091 100644 --- a/example/src/Examples/FABExample.tsx +++ b/example/src/Examples/FABExample.tsx @@ -34,9 +34,9 @@ const variants: FabColor[] = [ 'primary', 'secondary', 'tertiary', - 'tonalPrimary', - 'tonalSecondary', - 'tonalTertiary', + 'primaryContainer', + 'secondaryContainer', + 'tertiaryContainer', 'custom', ]; @@ -91,7 +91,7 @@ const FABExample = () => { const { colors } = useTheme(); const insets = useSafeAreaInsets(); - const [variant, setVariant] = React.useState('tonalPrimary'); + const [variant, setVariant] = React.useState('primaryContainer'); const activeVariant = variant === 'custom' ? undefined : variant; const activeContainerColor = variant === 'custom' ? CUSTOM_CONTAINER_COLOR : undefined; @@ -187,6 +187,7 @@ const FABExample = () => { {type === 'icon' && ( { alignment={position} trigger={{ icon: 'pencil', + 'aria-label': 'Compose', variant: activeVariant, containerColor: activeContainerColor, size, diff --git a/src/components/FAB/Extended.tsx b/src/components/FAB/Extended.tsx index 17da09bd56..103d6cc6a7 100644 --- a/src/components/FAB/Extended.tsx +++ b/src/components/FAB/Extended.tsx @@ -38,7 +38,7 @@ export type Props = { */ label: string; /** - * Role-color preset. Defaults to `tonalPrimary`. + * Role-color preset. Defaults to `primaryContainer`. */ variant?: Variant; /** @@ -154,7 +154,7 @@ export type Props = { const Extended = ({ icon, label, - variant = 'tonalPrimary', + variant = 'primaryContainer', containerColor, contentColor, size = 'default', diff --git a/src/components/FAB/FAB.tsx b/src/components/FAB/FAB.tsx index fb30396939..17c8face9f 100644 --- a/src/components/FAB/FAB.tsx +++ b/src/components/FAB/FAB.tsx @@ -21,7 +21,7 @@ export type Props = { */ icon: IconSource; /** - * Role-color preset. Defaults to `tonalPrimary`. + * Role-color preset. Defaults to `primaryContainer`. */ variant?: Variant; /** @@ -118,7 +118,7 @@ export type Props = { */ const FAB = ({ icon, - variant = 'tonalPrimary', + variant = 'primaryContainer', size = 'default', visible = true, onPress, diff --git a/src/components/FAB/Menu.tsx b/src/components/FAB/Menu.tsx index e4884647d6..069b2bde17 100644 --- a/src/components/FAB/Menu.tsx +++ b/src/components/FAB/Menu.tsx @@ -122,23 +122,29 @@ export type MenuProps = { * tonal (container) role color. */ const getCloseVariant = (triggerVariant: Variant): Variant => { - if (triggerVariant === 'primary' || triggerVariant === 'tonalPrimary') { + if (triggerVariant === 'primary' || triggerVariant === 'primaryContainer') { return 'primary'; } - if (triggerVariant === 'secondary' || triggerVariant === 'tonalSecondary') { + if ( + triggerVariant === 'secondary' || + triggerVariant === 'secondaryContainer' + ) { return 'secondary'; } return 'tertiary'; }; const getItemsVariant = (triggerVariant: Variant): Variant => { - if (triggerVariant === 'primary' || triggerVariant === 'tonalPrimary') { - return 'tonalPrimary'; + if (triggerVariant === 'primary' || triggerVariant === 'primaryContainer') { + return 'primaryContainer'; } - if (triggerVariant === 'secondary' || triggerVariant === 'tonalSecondary') { - return 'tonalSecondary'; + if ( + triggerVariant === 'secondary' || + triggerVariant === 'secondaryContainer' + ) { + return 'secondaryContainer'; } - return 'tonalTertiary'; + return 'tertiaryContainer'; }; // Per-item delay used by the stagger. Compose uses a single SlowEffects-driven @@ -544,7 +550,7 @@ const Menu = ({ const isRTL = direction === 'rtl'; const insets = useSafeAreaInsets(); - const triggerVariant: Variant = trigger.variant ?? 'tonalPrimary'; + const triggerVariant: Variant = trigger.variant ?? 'primaryContainer'; const size: Size = trigger.size ?? 'default'; const openIcon: IconSource = trigger.icon; const openOnPress = trigger.onPress; diff --git a/src/components/FAB/Shell.tsx b/src/components/FAB/Shell.tsx index 83a71f72ed..52d8d7dc9a 100644 --- a/src/components/FAB/Shell.tsx +++ b/src/components/FAB/Shell.tsx @@ -29,7 +29,7 @@ import { getDimensions, resolveColors } from './utils'; import { useInternalTheme } from '../../core/theming'; import { useReduceMotion } from '../../theme/accessibility/ReduceMotionContext'; import { toRawSpring } from '../../theme/tokens/sys/motion'; -import type { Elevation, ThemeProp } from '../../theme/types'; +import type { ThemeProp } from '../../theme/types'; import type { ShapeToken } from '../../theme/utils/shape'; import type { IconSource } from '../Icon'; import Surface from '../Surface'; @@ -46,7 +46,7 @@ export type ShellProps = { */ label?: string; /** - * Role-color preset. Defaults to `tonalPrimary`. + * Role-color preset. Defaults to `primaryContainer`. */ variant?: Variant; /** @@ -77,11 +77,6 @@ export type ShellProps = { * Trailing-padding override. */ trailing?: number; - /** - * Resting elevation level. Defaults to the FAB's enabled-state elevation. - * Pass `0` to disable the shadow entirely. - */ - elevation?: Elevation; /** * When `false`, the shell animates out (scale + alpha) and stops accepting * touches. @@ -186,7 +181,7 @@ export type ShellProps = { const Shell = ({ icon, label, - variant = 'tonalPrimary', + variant = 'primaryContainer', size = 'default', containerColor, contentColor, @@ -194,7 +189,6 @@ const Shell = ({ iconSize, leading, trailing, - elevation = Tokens.stateElevation.enabled, visible = true, onPress, 'aria-label': ariaLabel = label, @@ -217,6 +211,19 @@ const Shell = ({ ref, }: ShellProps) => { const theme = useInternalTheme(themeOverrides); + const [hovered, setHovered] = React.useState(false); + const [pressed, setPressed] = React.useState(false); + const touchableRef = React.useRef(null); + const previousFocusedElement = React.useRef(null); + + const resolvedElevation = + visible && onPress + ? pressed + ? Tokens.stateElevation.pressed + : hovered + ? Tokens.stateElevation.hover + : Tokens.stateElevation.enabled + : Tokens.stateElevation.enabled; const dimensions = React.useMemo( () => getDimensions({ theme, size, shape, iconSize, leading, trailing }), @@ -299,6 +306,42 @@ const Shell = ({ const { focusedSV, onFocus, onBlur } = useFocusRing(); + React.useEffect(() => { + if (!visible) { + if (Platform.OS === 'web') { + const target: unknown = touchableRef.current; + if ( + target instanceof HTMLElement && + target === document.activeElement + ) { + const previous = previousFocusedElement.current; + // Only restore keyboard focus. A mouse click or tap also focuses the + // FAB, and moving focus back could jump into an earlier text field. + if ( + target.matches(':focus-visible') && + previous?.isConnected && + !previous.closest('[aria-hidden="true"], [inert]') + ) { + previous.focus({ preventScroll: true }); + } + // Blur when focus didn't move back, e.g. after a mouse click or when + // the previous element is gone or can't take focus. + if (target === document.activeElement) target.blur(); + } + } + setHovered(false); + setPressed(false); + onBlur(); + } + }, [visible, onBlur]); + + React.useEffect(() => { + if (!onPress) { + setHovered(false); + setPressed(false); + } + }, [onPress]); + const focusRingStyle = useAnimatedStyle( () => ({ opacity: focusedSV.value ? 1 : 0, @@ -310,6 +353,7 @@ const Shell = ({ return ( {overlay} setHovered(true)} + onHoverOut={() => setHovered(false)} + onPressIn={() => setPressed(true)} + onPressOut={() => setPressed(false)} + onFocus={(event) => { + if (Platform.OS === 'web') { + const previous = + 'relatedTarget' in event.nativeEvent + ? event.nativeEvent.relatedTarget + : null; + previousFocusedElement.current = + previous instanceof HTMLElement ? previous : null; + } + onFocus(); + }} onBlur={onBlur} aria-label={ariaLabel} role="button" diff --git a/src/components/FAB/tokens.ts b/src/components/FAB/tokens.ts index 0fb79d1d9c..c37a79ef0b 100644 --- a/src/components/FAB/tokens.ts +++ b/src/components/FAB/tokens.ts @@ -12,9 +12,9 @@ export type Variant = | 'primary' | 'secondary' | 'tertiary' - | 'tonalPrimary' - | 'tonalSecondary' - | 'tonalTertiary'; + | 'primaryContainer' + | 'secondaryContainer' + | 'tertiaryContainer'; export type Size = 'default' | 'medium' | 'large'; @@ -71,15 +71,15 @@ const variants = { primary: { container: 'primary', content: 'onPrimary' }, secondary: { container: 'secondary', content: 'onSecondary' }, tertiary: { container: 'tertiary', content: 'onTertiary' }, - tonalPrimary: { + primaryContainer: { container: 'primaryContainer', content: 'onPrimaryContainer', }, - tonalSecondary: { + secondaryContainer: { container: 'secondaryContainer', content: 'onSecondaryContainer', }, - tonalTertiary: { + tertiaryContainer: { container: 'tertiaryContainer', content: 'onTertiaryContainer', }, diff --git a/src/components/FAB/utils.ts b/src/components/FAB/utils.ts index cd894f048d..9c1a0eb72d 100644 --- a/src/components/FAB/utils.ts +++ b/src/components/FAB/utils.ts @@ -19,7 +19,7 @@ export type ResolvedColors = { */ export const resolveColors = ({ theme, - variant = 'tonalPrimary', + variant = 'primaryContainer', containerColor, contentColor, }: { diff --git a/src/components/__tests__/FAB.test.tsx b/src/components/__tests__/FAB.test.tsx index eedcb3e0f3..c696cf8ff8 100644 --- a/src/components/__tests__/FAB.test.tsx +++ b/src/components/__tests__/FAB.test.tsx @@ -1,9 +1,24 @@ -import { expect, it, jest } from '@jest/globals'; +import * as React from 'react'; +import { Platform, View } from 'react-native'; + +import { + afterEach, + beforeEach, + describe, + expect, + it, + jest, +} from '@jest/globals'; import { fireEvent, userEvent } from '@testing-library/react-native'; +import { getAnimatedStyle } from 'react-native-reanimated'; import { render, screen } from '../../test-utils'; import FAB from '../FAB'; +afterEach(() => { + jest.restoreAllMocks(); +}); + it('renders FAB with default props', async () => { const tree = (await render()).toJSON(); expect(tree).toMatchSnapshot(); @@ -24,16 +39,16 @@ it('renders FAB with tertiary variant', async () => { expect(tree).toMatchSnapshot(); }); -it('renders FAB with tonalSecondary variant', async () => { +it('renders FAB with secondaryContainer variant', async () => { const tree = ( - await render() + await render() ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB with tonalTertiary variant', async () => { +it('renders FAB with tertiaryContainer variant', async () => { const tree = ( - await render() + await render() ).toJSON(); expect(tree).toMatchSnapshot(); }); @@ -101,3 +116,382 @@ it('forwards event object to onPress', async () => { }); expect(onPress).toHaveBeenCalledWith({ key: 'value' }); }); + +const getStyle = (ref: React.RefObject) => { + if (!ref.current) throw new Error('Expected FAB ref to be attached'); + return getAnimatedStyle(ref.current); +}; + +// Android exposes elevation as a plain number, so the direction is checkable +// without the shadow tokens. +const getElevation = (ref: React.RefObject) => { + const style = getStyle(ref); + if (!('elevation' in style) || typeof style.elevation !== 'number') { + throw new Error('Expected a numeric elevation'); + } + return style.elevation; +}; + +it('renders a FAB without onPress as a disabled button', async () => { + await render(); + expect(screen.getByRole('button', { name: 'Create' })).toBeDisabled(); +}); + +it('hides an invisible FAB from accessibility and keyboard navigation without marking it disabled', async () => { + const onPress = jest.fn(); + await render( + + ); + expect(screen.queryByRole('button', { name: 'Create' })).toBeNull(); + const fab = screen.getByTestId('create', { includeHiddenElements: true }); + expect(fab).not.toBeDisabled(); + expect(fab).toHaveProp('accessible', false); + expect(fab).toHaveProp('focusable', false); + expect(fab).toHaveProp('tabIndex', -1); + await userEvent.press(fab); + await fireEvent(fab, 'click', { nativeEvent: {} }); + expect(onPress).not.toHaveBeenCalled(); +}); + +it('clears interaction elevation when a FAB is hidden and shown again', async () => { + const ref = React.createRef(); + const onPress = jest.fn(); + const { rerender } = await render( + + ); + const resting = getStyle(ref); + await fireEvent(screen.getByRole('button', { name: 'Create' }), 'hoverIn'); + expect(getStyle(ref)).not.toEqual(resting); + await rerender( + + ); + await rerender(); + expect(getStyle(ref)).toEqual(resting); +}); + +it('uses the shared FAB hover elevation for the menu trigger', async () => { + const { toJSON } = await render( + {}} + trigger={{ icon: 'plus', 'aria-label': 'Create', onPress: () => {} }} + items={[ + { label: 'First', onPress: () => {} }, + { label: 'Second', onPress: () => {} }, + ]} + /> + ); + const before = JSON.stringify(toJSON()); + await fireEvent(screen.getByRole('button', { name: 'Create' }), 'hoverIn'); + const hovered = JSON.stringify(toJSON()); + expect(hovered).not.toBe(before); + await fireEvent(screen.getByRole('button', { name: 'Create' }), 'hoverOut'); + expect(JSON.stringify(toJSON())).toBe(before); +}); + +// React Native 0.85 sends no hover events on iOS or Android by default. These +// only check that the elevation logic itself has no platform check. +it.each(['ios', 'android'] as const)( + 'keeps the resting elevation on focus and follows hover and press events when Platform.OS is %s', + async (platform) => { + jest.replaceProperty(Platform, 'OS', platform); + const ref = React.createRef(); + await render( + {}} + /> + ); + const fab = screen.getByRole('button', { name: 'Create' }); + const resting = getStyle(ref); + + await fireEvent(fab, 'focus', { nativeEvent: {} }); + expect(getStyle(ref)).toEqual(resting); + await fireEvent(fab, 'hoverIn'); + const hovered = getStyle(ref); + expect(hovered).not.toEqual(resting); + await fireEvent(fab, 'focus', { nativeEvent: {} }); + expect(getStyle(ref)).toEqual(hovered); + await fireEvent(fab, 'pressIn'); + expect(getStyle(ref)).toEqual(resting); + await fireEvent(fab, 'pressOut'); + expect(getStyle(ref)).toEqual(hovered); + await fireEvent(fab, 'hoverOut'); + expect(getStyle(ref)).toEqual(resting); + } +); + +it('raises the elevation while hovered and lowers it while pressed when Platform.OS is android', async () => { + jest.replaceProperty(Platform, 'OS', 'android'); + const ref = React.createRef(); + await render( + {}} + /> + ); + const fab = screen.getByRole('button', { name: 'Create' }); + const resting = getElevation(ref); + + await fireEvent(fab, 'hoverIn'); + expect(getElevation(ref)).toBeGreaterThan(resting); + await fireEvent(fab, 'pressIn'); + expect(getElevation(ref)).toBe(resting); +}); + +it('restores the resting elevation when a hovered FAB loses its action', async () => { + const ref = React.createRef(); + const { rerender } = await render( + {}} + /> + ); + const resting = getStyle(ref); + await fireEvent(screen.getByRole('button', { name: 'Create' }), 'hoverIn'); + expect(getStyle(ref)).not.toEqual(resting); + await rerender(); + expect(getStyle(ref)).toEqual(resting); + expect(screen.getByRole('button', { name: 'Create' })).toBeDisabled(); + await rerender( {}} />); + expect(getStyle(ref)).toEqual(resting); +}); + +describe('on web', () => { + const originalHTMLElement = Object.getOwnPropertyDescriptor( + globalThis, + 'HTMLElement' + ); + const originalDocument = Object.getOwnPropertyDescriptor( + globalThis, + 'document' + ); + const originalMatches = Object.getOwnPropertyDescriptor( + View.prototype, + 'matches' + ); + const originalComponentDidMount = Object.getOwnPropertyDescriptor( + View.prototype, + 'componentDidMount' + ); + let activeElement: unknown; + let focusVisible: boolean; + let fabElement: View | undefined; + + beforeEach(() => { + jest.replaceProperty(Platform, 'OS', 'web'); + activeElement = null; + focusVisible = true; + fabElement = undefined; + // Native View refs stand in for DOM elements in the native test renderer. + Object.defineProperty(globalThis, 'HTMLElement', { + configurable: true, + value: View, + }); + Object.defineProperty(globalThis, 'document', { + configurable: true, + value: { + get activeElement() { + return activeElement; + }, + }, + }); + Object.defineProperty(View.prototype, 'matches', { + configurable: true, + value: (selectors: string) => + selectors === ':focus-visible' && focusVisible, + }); + // The pressable view with the FAB's testID is the element that takes focus. + Object.defineProperty(View.prototype, 'componentDidMount', { + configurable: true, + value(this: View) { + if (this.props.testID === 'create') { + fabElement = this; + } + }, + }); + }); + + afterEach(() => { + for (const [target, key, descriptor] of [ + [globalThis, 'HTMLElement', originalHTMLElement], + [globalThis, 'document', originalDocument], + [View.prototype, 'matches', originalMatches], + [View.prototype, 'componentDidMount', originalComponentDidMount], + ] as const) { + if (descriptor) { + Object.defineProperty(target, key, descriptor); + } else { + Reflect.deleteProperty(target, key); + } + } + }); + + const createElement = ({ + isConnected = true, + focusable = true, + hiddenBy, + }: { + isConnected?: boolean; + focusable?: boolean; + hiddenBy?: string; + } = {}) => { + const element = new View({}); + return Object.assign(element, { + isConnected, + closest: (selectors: string) => + hiddenBy && selectors.includes(hiddenBy) ? {} : null, + // Like browsers, focus() does nothing on an element that can't take it. + focus: jest.fn(() => { + if (isConnected && focusable) { + activeElement = element; + } + }), + }); + }; + + const renderFocusedFAB = async (relatedTarget: unknown) => { + const fab = (visible: boolean) => ( + {}} + visible={visible} + /> + ); + const { rerender } = await render(fab(true)); + if (!fabElement) throw new Error('Expected the FAB to mount'); + activeElement = fabElement; + // The View mock shares one `blur` mock across instances. + const blur = jest.fn(); + fabElement.blur = blur; + await fireEvent(screen.getByRole('button', { name: 'Create' }), 'focus', { + nativeEvent: { relatedTarget }, + }); + return { blur, hide: () => rerender(fab(false)) }; + }; + + it.each(['icon', 'extended'] as const)( + 'keeps the %s FAB at rest on focus, changes its elevation while hovered and restores it while pressed', + async (type) => { + const ref = React.createRef(); + await render( + type === 'icon' ? ( + {}} + /> + ) : ( + {}} + /> + ) + ); + const fab = screen.getByRole('button', { name: 'Create' }); + const resting = getStyle(ref); + + await fireEvent(fab, 'focus', { nativeEvent: {} }); + expect(getStyle(ref)).toEqual(resting); + await fireEvent(fab, 'hoverIn'); + const hovered = getStyle(ref); + expect(hovered).not.toEqual(resting); + await fireEvent(fab, 'focus', { nativeEvent: {} }); + expect(getStyle(ref)).toEqual(hovered); + await fireEvent(fab, 'pressIn'); + expect(getStyle(ref)).toEqual(resting); + await fireEvent(fab, 'pressOut'); + expect(getStyle(ref)).toEqual(hovered); + await fireEvent(fab, 'hoverOut'); + expect(getStyle(ref)).toEqual(resting); + } + ); + + it('moves focus back to the previous element when a keyboard-focused FAB hides', async () => { + const previous = createElement(); + const { blur, hide } = await renderFocusedFAB(previous); + + await hide(); + + expect(previous.focus).toHaveBeenCalledWith({ preventScroll: true }); + expect(blur).not.toHaveBeenCalled(); + }); + + it.each([ + ['inside an aria-hidden subtree', { hiddenBy: '[aria-hidden="true"]' }], + ['inside an inert subtree', { hiddenBy: '[inert]' }], + ['disconnected', { isConnected: false }], + ])( + 'blurs a keyboard-focused FAB that hides when the previous element is %s', + async (_, options) => { + const previous = createElement(options); + const { blur, hide } = await renderFocusedFAB(previous); + + await hide(); + + expect(previous.focus).not.toHaveBeenCalled(); + expect(blur).toHaveBeenCalledTimes(1); + } + ); + + it("blurs a keyboard-focused FAB that hides when the previous element can't take focus", async () => { + const previous = createElement({ focusable: false }); + const { blur, hide } = await renderFocusedFAB(previous); + + await hide(); + + expect(previous.focus).toHaveBeenCalledWith({ preventScroll: true }); + expect(blur).toHaveBeenCalledTimes(1); + }); + + it('blurs a FAB focused by a mouse click instead of moving focus back', async () => { + focusVisible = false; + const previous = createElement(); + const { blur, hide } = await renderFocusedFAB(previous); + + await hide(); + + expect(previous.focus).not.toHaveBeenCalled(); + expect(blur).toHaveBeenCalledTimes(1); + }); + + it('leaves focus alone when a FAB that lost focus hides', async () => { + const previous = createElement(); + const { blur, hide } = await renderFocusedFAB(previous); + activeElement = createElement(); + + await hide(); + + expect(previous.focus).not.toHaveBeenCalled(); + expect(blur).not.toHaveBeenCalled(); + }); +}); diff --git a/src/components/__tests__/FABUtils.test.tsx b/src/components/__tests__/FABUtils.test.tsx index 9389ccd78d..d5bb8b87f0 100644 --- a/src/components/__tests__/FABUtils.test.tsx +++ b/src/components/__tests__/FABUtils.test.tsx @@ -1,10 +1,41 @@ import { describe, expect, it } from '@jest/globals'; -import { LightTheme } from '../../theme/schemes'; +import { DarkTheme, LightTheme } from '../../theme/schemes'; import { getDimensions, resolveColors } from '../FAB/utils'; describe('resolveColors', () => { - it('returns theme colors for default variant (tonalPrimary)', () => { + it.each([false, true])( + 'resolves every FAB color preset (dark=%s)', + (dark) => { + const theme = dark ? DarkTheme : LightTheme; + const variants = { + primary: ['primary', 'onPrimary'], + primaryContainer: ['primaryContainer', 'onPrimaryContainer'], + secondary: ['secondary', 'onSecondary'], + secondaryContainer: ['secondaryContainer', 'onSecondaryContainer'], + tertiary: ['tertiary', 'onTertiary'], + tertiaryContainer: ['tertiaryContainer', 'onTertiaryContainer'], + } as const; + + const variantNames = [ + 'primary', + 'primaryContainer', + 'secondary', + 'secondaryContainer', + 'tertiary', + 'tertiaryContainer', + ] as const; + for (const variant of variantNames) { + const [container, content] = variants[variant]; + expect(resolveColors({ theme, variant })).toEqual({ + container: theme.colors[container], + content: theme.colors[content], + }); + } + } + ); + + it('returns theme colors for default variant (primaryContainer)', () => { const colors = resolveColors({ theme: LightTheme }); expect(colors).toEqual({ container: LightTheme.colors.primaryContainer, @@ -36,10 +67,10 @@ describe('resolveColors', () => { }); }); - it('returns theme colors for tonalSecondary variant', () => { + it('returns theme colors for secondaryContainer variant', () => { const colors = resolveColors({ theme: LightTheme, - variant: 'tonalSecondary', + variant: 'secondaryContainer', }); expect(colors).toEqual({ container: LightTheme.colors.secondaryContainer, @@ -47,10 +78,10 @@ describe('resolveColors', () => { }); }); - it('returns theme colors for tonalTertiary variant', () => { + it('returns theme colors for tertiaryContainer variant', () => { const colors = resolveColors({ theme: LightTheme, - variant: 'tonalTertiary', + variant: 'tertiaryContainer', }); expect(colors).toEqual({ container: LightTheme.colors.tertiaryContainer, diff --git a/src/components/__tests__/__snapshots__/FAB.test.tsx.snap b/src/components/__tests__/__snapshots__/FAB.test.tsx.snap index 4b06302358..a1ed339730 100644 --- a/src/components/__tests__/__snapshots__/FAB.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/FAB.test.tsx.snap @@ -138,7 +138,7 @@ exports[`renders FAB large size 1`] = ` } accessible={true} collapsable={false} - focusable={true} + focusable={false} onBlur={[Function]} onClick={[Function]} onFocus={[Function]} @@ -377,7 +377,7 @@ exports[`renders FAB medium size 1`] = ` } accessible={true} collapsable={false} - focusable={true} + focusable={false} onBlur={[Function]} onClick={[Function]} onFocus={[Function]} @@ -480,6 +480,7 @@ exports[`renders FAB medium size 1`] = ` exports[`renders FAB transitioning to not visible 1`] = ` `; -exports[`renders FAB with tertiary variant 1`] = ` +exports[`renders FAB with secondaryContainer variant 1`] = ` `; -exports[`renders FAB with tonalSecondary variant 1`] = ` +exports[`renders FAB with tertiary variant 1`] = ` `; -exports[`renders FAB with tonalTertiary variant 1`] = ` +exports[`renders FAB with tertiaryContainer variant 1`] = `