Skip to content

Commit

Permalink
feat: toast
Browse files Browse the repository at this point in the history
  • Loading branch information
fbwoolf committed Mar 11, 2024
1 parent 5b37691 commit 44842b6
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 13 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
"@radix-ui/react-dropdown-menu": "2.0.6",
"@radix-ui/react-select": "2.0.0",
"@radix-ui/react-tabs": "1.0.4",
"@radix-ui/react-toast": "1.1.5",
"@radix-ui/react-tooltip": "1.0.7",
"@radix-ui/themes": "2.0.3",
"@reduxjs/toolkit": "1.9.6",
Expand Down
23 changes: 13 additions & 10 deletions src/app/app.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Suspense } from 'react';
import { Provider as ReduxProvider } from 'react-redux';

import { Provider as RadixToastProvider } from '@radix-ui/react-toast';
import { radixBaseCSS } from '@radix-ui/themes/styles.css';
import { QueryClientProvider } from '@tanstack/react-query';
import { styled } from 'leather-styles/jsx';
Expand All @@ -26,16 +27,18 @@ export function App() {
<HeadProvider />
{/* TODO: this works but investigate importing radixBaseCSS in panda layer config */}
<ThemeSwitcherProvider>
<styled.div css={radixBaseCSS}>
<QueryClientProvider client={queryClient}>
<Suspense fallback={<FullPageLoadingSpinner />}>
<AppErrorBoundary>
<AppRoutes />
</AppErrorBoundary>
{reactQueryDevToolsEnabled && <Devtools />}
</Suspense>
</QueryClientProvider>
</styled.div>
<RadixToastProvider duration={1000} label="Toast">
<styled.div css={radixBaseCSS}>
<QueryClientProvider client={queryClient}>
<Suspense fallback={<FullPageLoadingSpinner />}>
<AppErrorBoundary>
<AppRoutes />
</AppErrorBoundary>
{reactQueryDevToolsEnabled && <Devtools />}
</Suspense>
</QueryClientProvider>
</styled.div>
</RadixToastProvider>
</ThemeSwitcherProvider>
</PersistGate>
</ReduxProvider>
Expand Down
6 changes: 3 additions & 3 deletions src/app/features/html-head/head-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Link, HeadProvider as ReastHeadProvider, Title } from 'react-head';
import { Link, HeadProvider as ReactHeadProvider, Title } from 'react-head';

import { useNewBrandApprover } from '@app/store/settings/settings.selectors';

export function HeadProvider() {
const { hasApprovedNewBrand } = useNewBrandApprover();
return (
<ReastHeadProvider>
<ReactHeadProvider>
{hasApprovedNewBrand ? <LeatherMetaTags /> : <HiroMetaTags />}
</ReastHeadProvider>
</ReactHeadProvider>
);
}

Expand Down
54 changes: 54 additions & 0 deletions src/app/ui/components/toast/toast-primitive.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { forwardRef } from 'react';

import * as RadixToast from '@radix-ui/react-toast';
import { css } from 'leather-styles/css';

const toastRootStyles = css({
bg: 'ink.text-primary',
rounded: 'xs',
boxShadow:
'0px 12px 24px 0px rgba(18, 16, 15, 0.08), 0px 4px 8px 0px rgba(18, 16, 15, 0.08), 0px 0px 2px 0px rgba(18, 16, 15, 0.08)',
pl: 'space.03',
pr: 'space.04',
py: 'space.03',

'&[data-state=open]': {
animation: 'toastAppear 160ms cubic-bezier(0, 0.45, 0.6, 1) forwards',
},
'&[data-state=closed]': {
animation: 'fadeout',
},
});
const Root: typeof RadixToast.Root = forwardRef((props, ref) => (
<RadixToast.Root className={toastRootStyles} ref={ref} {...props} />
));

const toastViewportStyles = css({
display: 'flex',
flexDirection: 'column',
m: '0 auto',
maxWidth: 'fit-content',
outline: 'none',
p: 'space.05',
position: 'fixed',
top: 0,
zIndex: 9999,
});
const Viewport: typeof RadixToast.Viewport = forwardRef((props, ref) => (
<RadixToast.Viewport className={toastViewportStyles} ref={ref} {...props} />
));

const toastMessageStyles = css({
color: 'ink.background-primary',
fontWeight: 500,
textStyle: 'label.02',
});
const Title: typeof RadixToast.Title = forwardRef((props, ref) => (
<RadixToast.Title className={toastMessageStyles} ref={ref} {...props} />
));

export const ToastPrimitive = {
Root,
Viewport,
Title,
};
71 changes: 71 additions & 0 deletions src/app/ui/components/toast/toast.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Provider as RadixToastProvider } from '@radix-ui/react-toast';
import { Meta, StoryObj } from '@storybook/react';
import { styled } from 'leather-styles/jsx';

import { Toast as Component } from './toast';
import { ToastPrimitive } from './toast-primitive';

const meta: Meta<typeof Component> = {
component: Component,
tags: ['autodocs'],
title: 'Toast',
// argTypes: {
// variant: {
// options: ['error', 'info', 'success', 'undefined'],
// control: { type: 'radio' },
// defaultValue: 'info',
// },
// },
};

export default meta;
type Story = StoryObj<typeof Component>;

export const Toast: Story = {
parameters: {
controls: { include: ['variant'] },
},
render: args => (
<RadixToastProvider duration={1000} label="Toast">
<styled.div height="100px">
<Component open variant={args.variant}>
Placeholder message
</Component>
</styled.div>
<ToastPrimitive.Viewport />
</RadixToastProvider>
),
};

export const AnimatedInfo: Story = {
render: () => (
<RadixToastProvider duration={1000} label="Toast">
<styled.div height="100px">
<Component variant="info">Just a heads up</Component>
</styled.div>
<ToastPrimitive.Viewport />
</RadixToastProvider>
),
};

export const AnimatedSuccess: Story = {
render: () => (
<RadixToastProvider duration={1000} label="Toast">
<styled.div height="100px">
<Component variant="success">That worked well</Component>
</styled.div>
<ToastPrimitive.Viewport />
</RadixToastProvider>
),
};

export const AnimatedError: Story = {
render: () => (
<RadixToastProvider duration={1000} label="Toast">
<styled.div height="100px">
<Component variant="error">Something went wrong</Component>
</styled.div>
<ToastPrimitive.Viewport />
</RadixToastProvider>
),
};
23 changes: 23 additions & 0 deletions src/app/ui/components/toast/toast.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { type ToastProps } from '@radix-ui/react-toast';
import { HStack } from 'leather-styles/jsx';

import { ToastPrimitive } from './toast-primitive';
import { type ToastVariant, getIconVariant } from './toast.utils';

type ToastPrimitiveProps = ToastProps & React.RefAttributes<HTMLLIElement>;

interface TitleProps extends ToastPrimitiveProps {
variant: ToastVariant;
}
export function Toast({ children, variant, ...props }: TitleProps) {
return (
<ToastPrimitive.Root {...props}>
<ToastPrimitive.Title>
<HStack gap="space.03">
{getIconVariant(variant)}
{children}
</HStack>
</ToastPrimitive.Title>
</ToastPrimitive.Root>
);
}
16 changes: 16 additions & 0 deletions src/app/ui/components/toast/toast.utils.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { CheckmarkCircleIcon, ErrorIcon, InfoCircleIcon } from '@app/ui/icons';

export type ToastVariant = 'info' | 'success' | 'error';

export function getIconVariant(variant?: ToastVariant) {
switch (variant) {
case 'info':
return <InfoCircleIcon color="ink.ink.background-primary" />;
case 'success':
return <CheckmarkCircleIcon color="green.action-primary-default" />;
case 'error':
return <ErrorIcon color="red.action-primary-default" />;
default:
return <InfoCircleIcon color="ink.ink.background-primary" />;
}
}
4 changes: 4 additions & 0 deletions theme/keyframes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@ export const keyframes: CssKeyframes = {
from: { opacity: 1, transform: 'translateY(0)' },
to: { opacity: 0, transform: 'translateY(4px)' },
},
toastAppear: {
from: { opacity: 0, transform: 'translateY(-12px) scale(0.9)' },
to: { opacity: 1, transform: 'translateY(0) scale(1)' },
},
};
19 changes: 19 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3692,6 +3692,25 @@
"@radix-ui/react-roving-focus" "1.0.4"
"@radix-ui/react-use-controllable-state" "1.0.1"

"@radix-ui/[email protected]":
version "1.1.5"
resolved "https://registry.yarnpkg.com/@radix-ui/react-toast/-/react-toast-1.1.5.tgz#f5788761c0142a5ae9eb97f0051fd3c48106d9e6"
integrity sha512-fRLn227WHIBRSzuRzGJ8W+5YALxofH23y0MlPLddaIpLpCDqdE0NZlS2NRQDRiptfxDeeCjgFIpexB1/zkxDlw==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/primitive" "1.0.1"
"@radix-ui/react-collection" "1.0.3"
"@radix-ui/react-compose-refs" "1.0.1"
"@radix-ui/react-context" "1.0.1"
"@radix-ui/react-dismissable-layer" "1.0.5"
"@radix-ui/react-portal" "1.0.4"
"@radix-ui/react-presence" "1.0.1"
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-use-callback-ref" "1.0.1"
"@radix-ui/react-use-controllable-state" "1.0.1"
"@radix-ui/react-use-layout-effect" "1.0.1"
"@radix-ui/react-visually-hidden" "1.0.3"

"@radix-ui/[email protected]":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle-group/-/react-toggle-group-1.0.4.tgz#f5b5c8c477831b013bec3580c55e20a68179d6ec"
Expand Down

0 comments on commit 44842b6

Please sign in to comment.