Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Snackbar): update snackbar duration logic #1208

Merged
merged 7 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/__private_stories__/components-in-portals-story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ export const Default: StoryComponent = () => {
button={
<ButtonPrimary
aria-haspopup="dialog"
onPress={() => openSnackbar({message: 'Snackbar', withDismiss: true, duration: Infinity})}
onPress={() =>
openSnackbar({message: 'Snackbar', withDismiss: true, duration: 'PERSISTENT'})
}
aria-label="snackbar-button"
>
Open snackbar
Expand Down Expand Up @@ -165,7 +167,7 @@ export const Default: StoryComponent = () => {
openSnackbar({
message: 'Snackbar',
withDismiss: true,
duration: Infinity,
duration: 'PERSISTENT',
})
}
aria-label="sheet-snackbar-button"
Expand Down Expand Up @@ -202,7 +204,7 @@ export const Default: StoryComponent = () => {
openSnackbar({
message: 'Snackbar',
withDismiss: true,
duration: Infinity,
duration: 'PERSISTENT',
})
}
aria-label="sheet-snackbar-button"
Expand Down
12 changes: 4 additions & 8 deletions src/__stories__/snackbar-story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ export default {
type Args = {
buttonText: string;
message: string;
duration: string;
persistent: boolean;
type: React.ComponentProps<typeof Snackbar>['type'];
dismiss: boolean;
};

export const Default: StoryComponent<Args> = ({buttonText, message, duration, type, dismiss}) => {
const snackbarDuration = duration !== 'Default' ? +duration : undefined;
export const Default: StoryComponent<Args> = ({buttonText, message, persistent, type, dismiss}) => {
const snackbarDuration = persistent ? 'PERSISTENT' : undefined;
const {openSnackbar} = useSnackbar();
return (
<ButtonPrimary
Expand All @@ -35,14 +35,10 @@ Default.args = {
message: 'Some message',
buttonText: 'Action',
dismiss: false,
duration: 'Default',
persistent: false,
};

Default.argTypes = {
duration: {
options: ['Default', 'Infinity'],
control: {type: 'select'},
},
type: {
options: ['INFORMATIVE', 'CRITICAL'],
control: {type: 'select'},
Expand Down
14 changes: 7 additions & 7 deletions src/__tests__/snackbar-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ test('Snackbar', async () => {

render(
<ThemeContextProvider theme={makeTheme()}>
<Snackbar message="Some message" onClose={onCloseSpy} buttonText="Action" duration={Infinity} />
<Snackbar message="Some message" onClose={onCloseSpy} buttonText="Action" duration="PERSISTENT" />
</ThemeContextProvider>
);
expect(screen.getByText('Some message')).toBeInTheDocument();
Expand Down Expand Up @@ -61,7 +61,7 @@ test('Snackbar with dismiss button', async () => {
message="Some message"
onClose={onCloseSpy}
buttonText="Action"
duration={Infinity}
duration="PERSISTENT"
withDismiss
/>
</ThemeContextProvider>
Expand All @@ -87,7 +87,7 @@ test('Snackbar with dismiss button and custom label', async () => {
onClose={onCloseSpy}
buttonText="Action"
closeButtonLabel="custom close label"
duration={Infinity}
duration="PERSISTENT"
withDismiss
/>
</ThemeContextProvider>
Expand All @@ -106,7 +106,7 @@ test('Snackbar with dismiss button and custom label', async () => {
test('Snackbar does not have dismiss button by default', async () => {
render(
<ThemeContextProvider theme={makeTheme()}>
<Snackbar message="Some message" buttonText="Action" duration={Infinity} />
<Snackbar message="Some message" buttonText="Action" duration="PERSISTENT" />
</ThemeContextProvider>
);
const actionButton = await screen.findByRole('button', {name: 'Action'});
Expand All @@ -119,7 +119,7 @@ test('Snackbar always has dismiss button if it does not have action button and d
<ThemeContextProvider theme={makeTheme()}>
<Snackbar
message="Some message"
duration={Infinity}
duration="PERSISTENT"
withDismiss={false} // even when setting this to false explicitly
/>
</ThemeContextProvider>
Expand Down Expand Up @@ -165,7 +165,7 @@ test('nativeMessage is called with duration PERSISTENT when duration is Infinity
message="any-message"
onClose={onCloseSpy}
buttonText="any-button-text"
duration={Infinity}
duration="PERSISTENT"
/>
</ThemeContextProvider>
);
Expand Down Expand Up @@ -312,7 +312,7 @@ test('Snackbar with button aria-label', async () => {
onClose={onCloseSpy}
buttonText="Action"
buttonAccessibilityLabel="some a11y label"
duration={Infinity}
duration="PERSISTENT"
/>
</ThemeContextProvider>
);
Expand Down
15 changes: 8 additions & 7 deletions src/snackbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export type Props = {
buttonText?: string;
buttonAccessibilityLabel?: string;
closeButtonLabel?: string;
duration?: number;
duration?: 'PERSISTENT';
message: string;
onClose?: SnackbarCloseHandler;
type?: SnackbarType;
Expand Down Expand Up @@ -62,7 +62,8 @@ const SnackbarComponent = React.forwardRef<ImperativeHandle, Props>(
const longButtonWidth = isDesktopOrBigger ? 160 : 128;
const hasLongButton = buttonWidth > longButtonWidth;
const elementRef = React.useRef<HTMLDivElement>(null);
const shouldShowDismissButton = (duration === Infinity && !buttonText) || withDismiss;
const shouldShowDismissButton = (duration === 'PERSISTENT' && !buttonText) || withDismiss;
const defaultDuration = buttonText ? DEFAULT_DURATION_WITH_BUTTON : DEFAULT_DURATION_WITHOUT_BUTTON;

const onCloseRef = React.useRef(onClose);
React.useEffect(() => {
Expand All @@ -89,13 +90,15 @@ const SnackbarComponent = React.forwardRef<ImperativeHandle, Props>(
}, 50);

const closeTimeout =
duration !== Infinity ? setTimeout(() => close({action: 'TIMEOUT'}), duration) : undefined;
duration !== 'PERSISTENT'
? setTimeout(() => close({action: 'TIMEOUT'}), defaultDuration)
: undefined;

return () => {
clearTimeout(openTimeout);
clearTimeout(closeTimeout);
};
}, [close, duration]);
}, [close, duration, defaultDuration]);

return (
<Portal className={styles.snackbarContainer}>
Expand Down Expand Up @@ -203,8 +206,6 @@ const Snackbar = React.forwardRef<ImperativeHandle & HTMLDivElement, Props>(
},
ref
) => {
const defaultDuration = buttonText ? DEFAULT_DURATION_WITH_BUTTON : DEFAULT_DURATION_WITHOUT_BUTTON;
duration = Math.max(duration ?? defaultDuration, defaultDuration);
const renderNative = isWebViewBridgeAvailable();
const onCloseRef = React.useRef(onCloseProp);
const isOpenRef = React.useRef(false);
Expand All @@ -219,7 +220,7 @@ const Snackbar = React.forwardRef<ImperativeHandle & HTMLDivElement, Props>(
isOpenRef.current = true;
nativeMessage({
message,
duration: duration === Infinity ? 'PERSISTENT' : undefined,
duration,
buttonText,
buttonAccessibilityLabel,
type,
Expand Down
Loading