Merge branch 'andrehadianto/design-system-components' into andrehadianto/T-4869-toast

This commit is contained in:
Andre Hadianto
2024-02-22 23:42:47 +08:00
committed by GitHub
51 changed files with 1905 additions and 508 deletions
+3
View File
@@ -7,8 +7,11 @@
"@material-tailwind/react": "^2.1.7",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-radio-group": "^1.1.3",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toast": "^1.1.5",
"@radix-ui/react-tooltip": "^1.0.7",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
@@ -98,19 +98,29 @@ const Button = forwardRef<
href,
...baseLinkProps,
};
return <a {...externalLinkProps}>{_children}</a>;
return (
// @ts-expect-error - ref
<a ref={ref} {...externalLinkProps}>
{_children}
</a>
);
}
// Internal link
return (
<Link {...baseLinkProps} to={href}>
// @ts-expect-error - ref
<Link ref={ref} {...baseLinkProps} to={href}>
{_children}
</Link>
);
} else {
const { ...buttonProps } = _props;
// @ts-expect-error - as prop is not a valid prop for button elements
return <button {...buttonProps}>{_children}</button>;
return (
// @ts-expect-error - as prop is not a valid prop for button elements
<button ref={ref} {...buttonProps}>
{_children}
</button>
);
}
},
[],
@@ -161,8 +171,6 @@ const Button = forwardRef<
return (
<Component
{...props}
// @ts-expect-error - ref is not a valid prop for button elements
ref={ref}
className={buttonTheme({ ...styleProps, class: className })}
>
{cloneIcon(leftIcon, { ...iconSize })}
@@ -50,6 +50,7 @@ export const inputTheme = tv(
'outline-offset-0',
'outline-border-danger',
'shadow-none',
'focus:outline-border-danger',
],
helperText: 'text-elements-danger',
},
@@ -0,0 +1,54 @@
import { VariantProps, tv } from 'tailwind-variants';
export const radioTheme = tv({
slots: {
root: ['flex', 'gap-3', 'flex-wrap'],
wrapper: ['flex', 'items-center', 'gap-2', 'group'],
label: ['text-sm', 'tracking-[-0.006em]', 'text-elements-high-em'],
radio: [
'w-5',
'h-5',
'rounded-full',
'border',
'group',
'border-border-interactive/10',
'shadow-button',
'group-hover:border-border-interactive/[0.14]',
'focus-ring',
// Checked
'data-[state=checked]:bg-controls-primary',
'data-[state=checked]:group-hover:bg-controls-primary-hovered',
],
indicator: [
'flex',
'items-center',
'justify-center',
'relative',
'w-full',
'h-full',
'after:content-[""]',
'after:block',
'after:w-2.5',
'after:h-2.5',
'after:rounded-full',
'after:bg-transparent',
'after:group-hover:bg-controls-disabled',
'after:group-focus-visible:bg-controls-disabled',
// Checked
'after:data-[state=checked]:bg-elements-on-primary',
'after:data-[state=checked]:group-hover:bg-elements-on-primary',
'after:data-[state=checked]:group-focus-visible:bg-elements-on-primary',
],
},
variants: {
orientation: {
vertical: { root: ['flex-col'] },
horizontal: { root: ['flex-row'] },
},
},
defaultVariants: {
orientation: 'vertical',
},
});
export type RadioTheme = VariantProps<typeof radioTheme>;
@@ -0,0 +1,63 @@
import React from 'react';
import {
Root as RadixRoot,
RadioGroupProps,
} from '@radix-ui/react-radio-group';
import { RadioTheme, radioTheme } from './Radio.theme';
import { RadioItem, RadioItemProps } from './RadioItem';
export interface RadioOption extends RadioItemProps {
/**
* The label of the radio option.
*/
label: string;
/**
* The value of the radio option.
*/
value: string;
}
export interface RadioProps extends RadioGroupProps, RadioTheme {
/**
* The options of the radio.
* @default []
* @example
* ```tsx
* const options = [
* {
* label: 'Label 1',
* value: '1',
* },
* {
* label: 'Label 2',
* value: '2',
* },
* {
* label: 'Label 3',
* value: '3',
* },
* ];
* ```
*/
options: RadioOption[];
}
/**
* The Radio component is used to select one option from a list of options.
*/
export const Radio = ({
className,
options,
orientation,
...props
}: RadioProps) => {
const { root } = radioTheme({ orientation });
return (
<RadixRoot {...props} className={root({ className })}>
{options.map((option) => (
<RadioItem key={option.value} {...option} />
))}
</RadixRoot>
);
};
@@ -0,0 +1,74 @@
import React, { ComponentPropsWithoutRef } from 'react';
import {
Item as RadixRadio,
Indicator as RadixIndicator,
RadioGroupItemProps,
RadioGroupIndicatorProps,
} from '@radix-ui/react-radio-group';
import { radioTheme } from './Radio.theme';
export interface RadioItemProps extends RadioGroupItemProps {
/**
* The wrapper props of the radio item.
* You can use this prop to customize the wrapper props.
*/
wrapperProps?: ComponentPropsWithoutRef<'div'>;
/**
* The label props of the radio item.
* You can use this prop to customize the label props.
*/
labelProps?: ComponentPropsWithoutRef<'label'>;
/**
* The indicator props of the radio item.
* You can use this prop to customize the indicator props.
*/
indicatorProps?: RadioGroupIndicatorProps;
/**
* The id of the radio item.
*/
id?: string;
/**
* The label of the radio item.
*/
label?: string;
}
/**
* The RadioItem component is used to render a radio item.
*/
export const RadioItem = ({
className,
wrapperProps,
labelProps,
indicatorProps,
label,
id,
...props
}: RadioItemProps) => {
const { wrapper, label: labelClass, radio, indicator } = radioTheme();
// Generate a unique id for the radio item from the label if the id is not provided
const kebabCaseLabel = label?.toLowerCase().replace(/\s+/g, '-');
const componentId = id ?? kebabCaseLabel;
return (
<div className={wrapper({ className: wrapperProps?.className })}>
<RadixRadio {...props} className={radio({ className })} id={componentId}>
<RadixIndicator
forceMount
{...indicatorProps}
className={indicator({ className: indicatorProps?.className })}
/>
</RadixRadio>
{label && (
<label
{...labelProps}
className={labelClass({ className: labelProps?.className })}
htmlFor={componentId}
>
{label}
</label>
)}
</div>
);
};
@@ -0,0 +1,2 @@
export * from './Radio';
export * from './RadioItem';
@@ -0,0 +1,84 @@
import { tv, type VariantProps } from 'tailwind-variants';
export const switchTheme = tv({
slots: {
wrapper: ['flex', 'items-start', 'gap-4', 'w-[375px]'],
switch: [
'h-6',
'w-12',
'rounded-full',
'transition-all',
'duration-500',
'relative',
'cursor-default',
'shadow-inset',
'focus-ring',
'outline-none',
],
thumb: [
'block',
'h-4',
'w-4',
'translate-x-1',
'transition-transform',
'duration-100',
'will-change-transform',
'rounded-full',
'shadow-button',
'data-[state=checked]:translate-x-7',
'bg-controls-elevated',
],
label: [
'flex',
'flex-1',
'flex-col',
'px-1',
'gap-1',
'text-sm',
'text-elements-high-em',
'tracking-[-0.006em]',
],
description: ['text-xs', 'text-elements-low-em'],
},
variants: {
checked: {
true: {
switch: [
'bg-controls-primary',
'hover:bg-controls-primary-hovered',
'focus-visible:bg-controls-primary-hovered',
],
},
false: {
switch: [
'bg-controls-inset',
'hover:bg-controls-inset-hovered',
'focus-visible:bg-controls-inset-hovered',
],
},
},
disabled: {
true: {
switch: ['bg-controls-disabled', 'cursor-not-allowed'],
thumb: ['bg-elements-on-disabled'],
},
},
fullWidth: {
true: {
wrapper: ['w-full', 'justify-between'],
},
},
},
compoundVariants: [
{
checked: true,
disabled: true,
class: {
switch: ['bg-controls-disabled-active'],
thumb: ['bg-snowball-900'],
},
},
],
});
export type SwitchVariants = VariantProps<typeof switchTheme>;
@@ -0,0 +1,85 @@
import React, { type ComponentPropsWithoutRef } from 'react';
import { type SwitchProps as SwitchRadixProps } from '@radix-ui/react-switch';
import * as SwitchRadix from '@radix-ui/react-switch';
import { switchTheme, type SwitchVariants } from './Switch.theme';
interface SwitchProps
extends Omit<SwitchRadixProps, 'checked'>,
SwitchVariants {
/**
* The label of the switch.
*/
label?: string;
/**
* The description of the switch.
*/
description?: string;
/**
* Custom wrapper props for the switch.
*/
wrapperProps?: ComponentPropsWithoutRef<'div'>;
/**
* Function that is called when the checked state of the switch changes.
* @param checked The new checked state of the switch.
*/
onCheckedChange?(checked: boolean): void;
}
/**
* A switch is a component used for toggling between two states.
*/
export const Switch = ({
className,
checked,
label,
description,
disabled,
name,
wrapperProps,
fullWidth,
...props
}: SwitchProps) => {
const {
wrapper,
switch: switchClass,
thumb,
label: labelClass,
description: descriptionClass,
} = switchTheme({
checked,
disabled,
fullWidth,
});
const switchComponent = (
<SwitchRadix.Root
{...props}
checked={checked}
disabled={disabled}
className={switchClass({ className })}
>
<SwitchRadix.Thumb className={thumb()} />
</SwitchRadix.Root>
);
// If a label is provided, wrap the switch in a label element.
if (label) {
return (
<div
{...wrapperProps}
className={wrapper({ className: wrapperProps?.className })}
>
<label className={labelClass()} htmlFor={name}>
{label}
{description && (
<span className={descriptionClass()}>{description}</span>
)}
</label>
{switchComponent}
</div>
);
}
return switchComponent;
};
@@ -0,0 +1 @@
export * from './Switch';
@@ -9,6 +9,8 @@ export const tabsTheme = tv({
// Horizontal default
'px-1',
'pb-5',
'cursor-default',
'select-none',
'text-elements-low-em',
'border-b-2',
'border-transparent',
@@ -0,0 +1,14 @@
import { tv } from 'tailwind-variants';
export const tooltipTheme = tv({
slots: {
content: [
'z-tooltip',
'rounded-md',
'bg-surface-high-contrast',
'p-2',
'text-elements-on-high-contrast',
],
arrow: ['fill-surface-high-contrast'],
},
});
@@ -0,0 +1,47 @@
import React from 'react';
import type {
TooltipContentProps,
TooltipTriggerProps,
} from '@radix-ui/react-tooltip';
import { ReactNode, useState } from 'react';
import { TooltipBase, type TooltipBaseProps } from './TooltipBase';
export interface TooltipProps extends TooltipBaseProps {
triggerProps?: TooltipTriggerProps;
contentProps?: TooltipContentProps;
content?: ReactNode;
}
// https://github.com/radix-ui/primitives/issues/955#issuecomment-1798201143
// Wrap on top of Tooltip base to make tooltip open on mobile via click
export const Tooltip = ({
children,
triggerProps,
contentProps,
content,
...props
}: TooltipProps) => {
const [isTooltipVisible, setIsTooltipVisible] = useState(false);
return (
<TooltipBase
open={isTooltipVisible}
onOpenChange={setIsTooltipVisible}
{...props}
>
<TooltipBase.Trigger
asChild
onBlur={() => setIsTooltipVisible(false)}
onClick={() => setIsTooltipVisible((prevOpen) => !prevOpen)}
onFocus={() => setTimeout(() => setIsTooltipVisible(true), 0)}
{...triggerProps}
>
{triggerProps?.children ?? children}
</TooltipBase.Trigger>
<TooltipBase.Content {...contentProps}>
{content ?? contentProps?.children ?? 'Coming soon'}
</TooltipBase.Content>
</TooltipBase>
);
};
@@ -0,0 +1,38 @@
import React from 'react';
import {
Provider,
TooltipProps as RadixTooltipProps,
Root,
type TooltipProviderProps,
} from '@radix-ui/react-tooltip';
import { useState, type PropsWithChildren } from 'react';
import { TooltipContent } from './TooltipContent';
import { TooltipTrigger } from './TooltipTrigger';
export interface TooltipBaseProps extends RadixTooltipProps {
providerProps?: TooltipProviderProps;
}
export const TooltipBase = ({
children,
providerProps,
...props
}: PropsWithChildren<TooltipBaseProps>) => {
const [isTooltipVisible, setIsTooltipVisible] = useState(false);
return (
<Provider {...providerProps}>
<Root
open={isTooltipVisible}
onOpenChange={setIsTooltipVisible}
{...props}
>
{children}
</Root>
</Provider>
);
};
TooltipBase.Trigger = TooltipTrigger;
TooltipBase.Content = TooltipContent;
@@ -0,0 +1,46 @@
import React from 'react';
import {
Arrow,
Content,
Portal,
type TooltipArrowProps,
type TooltipContentProps,
} from '@radix-ui/react-tooltip';
import { tooltipTheme } from '../Tooltip.theme';
export interface ContentProps extends TooltipContentProps {
hasArrow?: boolean;
arrowProps?: TooltipArrowProps;
}
export const TooltipContent = ({
children,
arrowProps,
className,
hasArrow = true,
...props
}: ContentProps) => {
const { content, arrow } = tooltipTheme();
return (
<Portal>
<Content
className={content({
className,
})}
sideOffset={5}
{...props}
>
{hasArrow && (
<Arrow
className={arrow({
className: arrowProps?.className,
})}
{...arrowProps}
/>
)}
{children}
</Content>
</Portal>
);
};
@@ -0,0 +1 @@
export * from './TooltipContent';
@@ -0,0 +1,12 @@
import React from 'react';
import { Trigger, type TooltipTriggerProps } from '@radix-ui/react-tooltip';
export type TriggerProps = TooltipTriggerProps;
export const TooltipTrigger = ({ children, ...props }: TriggerProps) => {
return (
<Trigger asChild {...props}>
{children}
</Trigger>
);
};
@@ -0,0 +1 @@
export * from './TooltipTrigger';
@@ -0,0 +1,2 @@
export * from './Tooltip';
export * from './TooltipBase';
@@ -10,6 +10,7 @@ import { renderBadges } from './renders/badge';
import {
renderButtonIcons,
renderButtons,
renderDisabledButtons,
renderLinks,
} from './renders/button';
import {
@@ -17,16 +18,22 @@ import {
renderTabs,
renderVerticalTabs,
} from './renders/tabs';
import { Switch } from 'components/shared/Switch';
import { RADIO_OPTIONS } from './renders/radio';
import { Radio } from 'components/shared/Radio';
import {
renderInlineNotificationWithDescriptions,
renderInlineNotifications,
} from './renders/inlineNotifications';
import { renderInputs } from './renders/input';
import { renderToast, renderToastsWithCta } from './renders/toast';
import { renderTooltips } from './renders/tooltip';
const Page = () => {
const [singleDate, setSingleDate] = useState<Value>();
const [dateRange, setDateRange] = useState<Value>();
const [switchValue, setSwitchValue] = useState(false);
const [selectedRadio, setSelectedRadio] = useState<string>('');
return (
<div className="relative h-full min-h-full">
@@ -52,17 +59,47 @@ const Page = () => {
{/* Button */}
<div className="flex flex-col gap-10 items-center justify-between">
<h1 className="text-2xl font-bold">Tooltip</h1>
<div className="flex w-full flex-wrap max-w-[680px] justify-center gap-10">
{renderTooltips()}
</div>
<div className="w-full h border border-gray-200 px-20 my-10" />
{/* Input */}
<h1 className="text-2xl font-bold">Input</h1>
<div className="flex w-full flex-col gap-10">{renderInputs()}</div>
<div className="w-full h border border-gray-200 px-20 my-10" />
{/* Button */}
<h1 className="text-2xl font-bold">Button</h1>
<div className="flex flex-col gap-10">
{renderButtons()}
{renderButtonIcons()}
</div>
{/* Link */}
<div className="flex flex-col gap-10 items-center justify-between">
<h1 className="text-2xl font-bold">Link</h1>
<div className="flex gap-4 items-center justify-center">
{renderLinks()}
</div>
</div>
{/* Disabled button, icon only, and link */}
<div className="flex flex-col gap-10 items-center justify-between">
<div className="flex flex-col gap-2">
<h1 className="text-2xl font-bold text-center">Disabled</h1>
<p className="text-lg text-center text-gray-500">
Button icon only link
</p>
</div>
<div className="flex gap-10 items-center justify-center">
{renderDisabledButtons()}
</div>
</div>
<div className="w-full h border border-gray-200 px-20 my-10" />
{/* Badge */}
@@ -139,6 +176,49 @@ const Page = () => {
<div className="w-full h border border-gray-200 px-20 my-10" />
{/* Switch */}
<div className="flex flex-col gap-10 items-center justify-between">
<h1 className="text-2xl font-bold">Switch</h1>
<div className="flex flex-col gap-10 items-center justify-center">
<Switch
label="Label"
checked={switchValue}
onCheckedChange={setSwitchValue}
/>
<Switch
label="Label"
description="Additional information or context"
checked={switchValue}
onCheckedChange={setSwitchValue}
/>
<Switch disabled label="Disabled unchecked" />
<Switch disabled checked label="Disabled checked" />
</div>
</div>
<div className="w-full h border border-gray-200 px-20 my-10" />
{/* Radio */}
<div className="flex flex-col gap-10 items-center justify-between">
<h1 className="text-2xl font-bold">Radio</h1>
<div className="flex gap-20 items-start">
<Radio
options={RADIO_OPTIONS}
orientation="vertical"
value={selectedRadio}
onValueChange={setSelectedRadio}
/>
<Radio
options={RADIO_OPTIONS}
orientation="horizontal"
value={selectedRadio}
onValueChange={setSelectedRadio}
/>
</div>
</div>
<div className="w-full h border border-gray-200 px-20 my-10" />
{/* Inline notification */}
<div className="flex flex-col gap-10 items-center justify-between">
<h1 className="text-2xl font-bold">Inline Notification</h1>
@@ -149,16 +229,6 @@ const Page = () => {
{renderInlineNotificationWithDescriptions()}
</div>
</div>
<div className="w-full h border border-gray-200 px-20 my-10" />
{/* Link */}
<div className="flex flex-col gap-10 items-center justify-between">
<h1 className="text-2xl font-bold">Link</h1>
<div className="flex gap-4 items-center justify-center">
{renderLinks()}
</div>
</div>
</div>
</div>
</div>
@@ -2,44 +2,45 @@ import { Button, ButtonTheme } from 'components/shared/Button';
import { PlusIcon } from 'components/shared/CustomIcon';
import React from 'react';
const buttonVariants = ['primary', 'secondary', 'tertiary', 'danger'] as const;
const buttonSizes = ['lg', 'md', 'sm', 'xs'] as const;
const iconOnlyVariants = [
'primary',
'secondary',
'tertiary',
'ghost',
'danger',
'danger-ghost',
] as const;
const linkVariants = ['link', 'link-emphasized'] as const;
export const renderButtons = () => {
return ['primary', 'secondary', 'tertiary', 'danger'].map(
(variant, index) => (
<div className="flex gap-5 flex-wrap" key={index}>
{['lg', 'md', 'sm', 'xs', 'disabled'].map((size) => (
<Button
leftIcon={<PlusIcon />}
rightIcon={<PlusIcon />}
variant={variant as ButtonTheme['variant']}
size={size !== 'disabled' ? (size as ButtonTheme['size']) : 'md'}
key={`${variant}-${size}`}
disabled={size === 'disabled'}
>
Button
</Button>
))}
</div>
),
);
return buttonVariants.map((variant, index) => (
<div className="flex gap-5 flex-wrap" key={index}>
{buttonSizes.map((size) => (
<Button
leftIcon={<PlusIcon />}
rightIcon={<PlusIcon />}
variant={variant as ButtonTheme['variant']}
size={size as ButtonTheme['size']}
key={`${variant}-${size}`}
>
Button
</Button>
))}
</div>
));
};
export const renderButtonIcons = () => {
return [
'primary',
'secondary',
'tertiary',
'ghost',
'danger',
'danger-ghost',
].map((variant, index) => (
return iconOnlyVariants.map((variant, index) => (
<div className="flex gap-5 flex-wrap" key={index}>
{['lg', 'md', 'sm', 'xs', 'disabled'].map((size) => (
{buttonSizes.map((size) => (
<Button
iconOnly
variant={variant as ButtonTheme['variant']}
size={size !== 'disabled' ? (size as ButtonTheme['size']) : 'md'}
size={size as ButtonTheme['size']}
key={`${variant}-${size}`}
disabled={size === 'disabled'}
>
<PlusIcon />
</Button>
@@ -49,17 +50,38 @@ export const renderButtonIcons = () => {
};
export const renderLinks = () => {
return ['link', 'link-emphasized', 'disabled'].map((variant) => (
return linkVariants.map((variant) => (
<Button
variant={
variant !== 'disabled' ? (variant as ButtonTheme['variant']) : 'link'
}
variant={variant}
key={variant}
leftIcon={<PlusIcon />}
rightIcon={<PlusIcon />}
disabled={variant === 'disabled'}
>
Link
</Button>
));
};
export const renderDisabledButtons = () => {
return (
<>
{/* Button variants */}
<Button leftIcon={<PlusIcon />} rightIcon={<PlusIcon />} disabled>
Button
</Button>
{/* Icon only variants */}
<Button iconOnly disabled>
<PlusIcon />
</Button>
{/* Link variantws */}
<Button
variant="link"
disabled
leftIcon={<PlusIcon />}
rightIcon={<PlusIcon />}
>
Link
</Button>
</>
);
};
@@ -0,0 +1,16 @@
import { RadioOption } from 'components/shared/Radio';
export const RADIO_OPTIONS: RadioOption[] = [
{
label: 'Label 1',
value: '1',
},
{
label: 'Label 2',
value: '2',
},
{
label: 'Label 3',
value: '3',
},
];
@@ -0,0 +1,30 @@
import React from 'react';
import { Button } from 'components/shared/Button';
import { Tooltip } from 'components/shared/Tooltip';
import { ContentProps } from 'components/shared/Tooltip/TooltipContent';
const alignments: ContentProps['align'][] = ['start', 'center', 'end'];
const sides: ContentProps['side'][] = ['left', 'top', 'bottom', 'right'];
export const renderTooltips = () => {
const tooltips = sides.map((side) => {
return alignments.map((align) => {
return (
<Tooltip
key={`${side}-${align}`}
content="tooltip content"
contentProps={{ align, side }}
>
<Button
variant="ghost"
key={`${side}-${align}`}
className="h-16 self-center"
>
Tooltip ({side} - {align})
</Button>
</Tooltip>
);
});
});
return tooltips;
};
@@ -16,6 +16,7 @@ const DEFAULT_FILTER_VALUE: FilterValue = {
searchedBranch: '',
status: StatusOptions.ALL_STATUS,
};
const FETCH_DEPLOYMENTS_INTERVAL = 5000;
const DeploymentsTabPanel = () => {
const client = useGQLClient();
@@ -26,22 +27,30 @@ const DeploymentsTabPanel = () => {
const [deployments, setDeployments] = useState<Deployment[]>([]);
const [prodBranchDomains, setProdBranchDomains] = useState<Domain[]>([]);
const fetchDeployments = async () => {
const fetchDeployments = useCallback(async () => {
const { deployments } = await client.getDeployments(project.id);
setDeployments(deployments);
};
}, [client, project]);
const fetchProductionBranchDomains = useCallback(async () => {
const { domains } = await client.getDomains(project.id, {
branch: project.prodBranch,
});
setProdBranchDomains(domains);
}, []);
}, [client, project]);
useEffect(() => {
fetchDeployments();
fetchProductionBranchDomains();
}, []);
fetchDeployments();
const interval = setInterval(() => {
fetchDeployments();
}, FETCH_DEPLOYMENTS_INTERVAL);
return () => {
clearInterval(interval);
};
}, [fetchDeployments, fetchProductionBranchDomains]);
const currentDeployment = useMemo(() => {
return deployments.find((deployment) => {
+7 -3
View File
@@ -8,10 +8,13 @@ export default withMT({
'../../node_modules/@material-tailwind/react/theme/components/**/*.{js,ts,jsx,tsx}',
],
theme: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
extend: {
zIndex: {
tooltip: '52',
},
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
fontSize: {
'2xs': '0.625rem',
'3xs': '0.5rem',
@@ -151,6 +154,7 @@ export default withMT({
calendar:
'0px 3px 20px rgba(8, 47, 86, 0.1), 0px 0px 4px rgba(8, 47, 86, 0.14)',
field: '0px 1px 2px rgba(0, 0, 0, 0.04)',
inset: 'inset 0px 1px 0px rgba(8, 47, 86, 0.06)',
},
spacing: {
2.5: '0.625rem',